Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Abstract

In this notebook, readers will see how different expressions in a computer program get evaluated to different types of values. With variables, programmers can assign a meaningful name, known as an identifier, to a value of various types without having to worry about where it should be stored and transferred in the physical storage unit for computations. At this point, readers may regard identifiers simply as variables that can take different values, although this model will be refined later with the concepts of aliasing and mutations.

import sys  # to access system-specific parameters
from dis import dis  # for disassembly of bytecode
from ipywidgets import interact  # for interactive user interface controls

Values

Programming is the art of instructing a computer to perform tasks by manipulating data, which is represented as values. In mathematical terms, a computer (programming language) is essentially a set of rules for how values are stored and manipulated. In other words, values are the building blocks of computation, and they represent a specific piece of data that can be manipulated in various ways.

Integers

While a machine language only uses binary numbers as values, a high-level programming language provides more flexible and expressive ways to represent and manipulate values.

In Python, for instance, we can enter an integer in different number systems as follows.

# in decimal (base 10)
15
15
# in 'b'inary (base 2)
0b1111
15
# in 'o'ctadecimal (base 8)
0o17
15
# in he'x'adecimal (base 16)
0xF
15

All the above expressions are integer literals, namely, integers written out literally. They have the same numerical value, which gets printed in decimal by default.

%%hermes --no-context
Explain briefly how to redefine the equality operator in Python so that 
0 is equal to 1?
Loading...
🌿 Fork/new: main (will create on click)

There are also expressions with integer values but are not integer literals:

4 + 5 + 6
15
pow(2, 4) - 1
15
### BEGIN SOLUTION
# There is (in principle) no limit on how big an integer can be
10 ** sys.get_int_max_str_digits()  # this is okay as long as it is not printed!
10 ** sys.get_int_max_str_digits() - 1
### END SOLUTION
# SPOILER: Printing an integer actually involves converting it to a string!
%%hermes --no-context
Use a simple analogy to explain in a short paragraph how can a computer 
represent all integers using variable-length code?
Loading...
🌿 Fork/new: main (will create on click)

Strings

A string value is a sequence of characters that can be written literally using quotes:

# single quote
print("\U0001f600:\n\tI'm a string.")
😀:
	I'm a string.
# double quote
print("\N{grinning face}:\n\tI'm a string.")
😀:
	I'm a string.
# triple double quote
print(
    """😀:
	I'm a string."""
)
😀:
	I'm a string.

Note that all the literals represent the same value:

Escape sequence

\U0001f600 and \N{grinning face} are escape sequences representing the same grinning face emoji 😀 where

  • 0001f600 is the unicode in hexadecimal,

  • grinning face is the name, and

  • \ is called the escape symbol.

Control code

\n and \t are control code that does not represent any symbol.

  • \n creates a new line when printing the string.

  • \t creates a tab to indent the line.

Why a string value is often quoted in a computer program? Let’s ask AI:

%%hermes --no-context
Say your name.
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)
%%hermes --no-context
Say "your name".
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

An example is worth a thousand words, but exceptions often exist:

%%hermes --no-context
Are there programming languages that do not quote its string? Why?
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

The following is yet another way to print the same string:

print("\N{grinning face}:", "\tI'm a string.", sep="\n")
😀:
	I'm a string.

It is an elegant one-liner where

  • sep="\n" is a keyword argument that specifies the separator of the list of strings.

  • The default separator is a single space character, i.e., sep=" ".

In a notebook, we can get the docstring (document string) of a function conveniently using the symbol ? such as ?print or

print?
Signature: print(*args, sep=' ', end='\n', file=None, flush=False) Docstring: Prints the values to a stream, or to sys.stdout by default. sep string inserted between values, default a space. end string appended after the last value, default a newline. file a file-like object (stream); defaults to the current sys.stdout. flush whether to forcibly flush the stream. Type: builtin_function_or_method

We can also use the contextual help by placing the cursor over a function name and

  • click the menu item Help→\toShow Contextual Help or

  • press the short-cut key Shift + Tab.

### BEGIN SOLUTION
# install art module
%pip install art >/dev/null 2>&1
import art
import datetime
now = datetime.datetime.now()

yyyy, mm = str(now.year), "09" if now.month >= 9 else "02"
art.tprint(
    f"""{yyyy}{mm}CS1302
Intro to Comp Progm'g"""
)
### END SOLUTION
Note: you may need to restart the kernel to use updated packages.
 ____    ___   ____    __     ___   ____    ____  ____   _  _____   ___   ____  
|___ \  / _ \ |___ \  / /_   / _ \ |___ \  / ___|/ ___| / ||___ /  / _ \ |___ \ 
  __) || | | |  __) || '_ \ | | | |  __) || |    \___ \ | |  |_ \ | | | |  __) |
 / __/ | |_| | / __/ | (_) || |_| | / __/ | |___  ___) || | ___) || |_| | / __/ 
|_____| \___/ |_____| \___/  \___/ |_____| \____||____/ |_||____/  \___/ |_____|
                                                                                
 ___         _                  _             ____                            ____                                  _        
|_ _| _ __  | |_  _ __   ___   | |_   ___    / ___|  ___   _ __ ___   _ __   |  _ \  _ __   ___    __ _  _ __ ___  ( )  __ _ 
 | | | '_ \ | __|| '__| / _ \  | __| / _ \  | |     / _ \ | '_ ` _ \ | '_ \  | |_) || '__| / _ \  / _` || '_ ` _ \ |/  / _` |
 | | | | | || |_ | |   | (_) | | |_ | (_) | | |___ | (_) || | | | | || |_) | |  __/ | |   | (_) || (_| || | | | | |   | (_| |
|___||_| |_| \__||_|    \___/   \__| \___/   \____| \___/ |_| |_| |_|| .__/  |_|    |_|    \___/  \__, ||_| |_| |_|    \__, |
                                                                     |_|                          |___/                |___/ 

Check if AI can understand your message, such as the ones below:

%%hermes --no-context
Explain what you see in the following:
 (ง •̀_•́)ง 
 ╰(●’◡’●)╮ 
 (..•˘_˘•..)
 (づ ̄ 3 ̄)づ
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

User Input

Instead of entering a value in a program, a programmer can get user input values at runtime, i.e., when a program executes:

print("Your name is", input("Please input your name: ") + ".")
  • The input method prints its argument, if any, as a prompt.

  • The method takes user’s input and returns it as a string.

  • There is no need to delimit the input string by quotation marks. Simply press enter after typing a string.

print("My name is", print("Python"))
Python
My name is None
Solution to Exercise 3 #
  • Unlike input, the function print does not return the string it is trying to print. Printing a string is, therefore, different from returning a string.

  • print actually returns a None object that gets printed as None.

%%hermes --no-context
Explain whether the Python print function returns the value it prints.
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

Variables

A complicated computation often needs to be broken down into many basic computations, with intermediate values stored and transferred to different memory locations. Keeping track of where a value is written, and allocating free memory locations to write to, are not only burdensome but also error-prone.

This is where the concept of variables comes in—they serve as a logical (as opposed to physical) unit of storage that abstracts away the complexities of memory management.

Assignment

To define a variable, we can use the assignment operator = as follows:

x = 15

What does the above code mean?

  1. xx is equal to 15?

  2. xx is defined to be 15?

Let’s discover the truth by executing the following assignments step-by-step using %%pytutor magic:

%%pytutor
x = 15
x = x + 1
Loading...

In the second assignment, does it mean:

  1. xx is equal to xx+1?

  2. xx is defined to be xx+1?

If we say yes to the above questions, the value of xx should be ±∞\pm\infty. (Why?)

%%hermes --no-context
What is the solution to $x+1=x$ for $x$ in the extended real line?
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

To see how the Python interpreter carries out the assignment operation, the following code compiles the Python code to bytecode (similar to machine code) and displays it in assembly language.[1]

dis(compile('x = x + 1', '_', 'exec'))
  0           0 RESUME                   0

  1           2 LOAD_NAME                0 (x)
              4 LOAD_CONST               0 (1)
              6 BINARY_OP                0 (+)
             10 STORE_NAME               0 (x)
             12 RETURN_CONST             1 (None)

It is possible to assign different values to multiple variables in one line using the so-called tuple assignment syntax:

x, y, z = "15", "30", 15
x, y, z
('15', '30', 15)

One can also assign the same value to different variables in one line using a chained assignment:

x = y = z = 0
x, y, z
(0, 0, 0)

Once defined, a variable can be deleted using the del keyword. Accessing a variable that has not been assigned any value raises an error.

x = y = 1+1j
del x
x
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[72], line 3
      1 x = y = 1+1j
      2 del x
----> 3 x

NameError: name 'x' is not defined
%%hermes --no-context
How would you define constants in Python? Are literals also constants?
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

Identifiers

One reason why Python is expressive is that it affords programmers a significant amount of flexibility when it comes to choosing variable names. For instance, identifiers, such as variable names, are case-sensitive and of unlimited length, unlike older languages such as Pascal and Fortran. This flexibility also makes the program more readable. For instance, consider the following program:

def name():
    return first.name + last.name

first.name = "John"
last.name = "Smith"
print(name())
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[73], line 4
      1 def name():
      2     return first.name + last.name
      3 
----> 4 first.name = "John"
      5 last.name = "Smith"
      6 print(name())

NameError: name 'first' is not defined

Unfortunately, the program fails in the middle, why? Let’s take a closer look at the operations involved:

dis(compile("first.name + last.name", "_", "eval"))
  0           RESUME                   0

  1           LOAD_NAME                0 (first)
              LOAD_ATTR                2 (name)
              LOAD_NAME                2 (last)
              LOAD_ATTR                2 (name)
              BINARY_OP                0 (+)
              RETURN_VALUE

How about the following fix?

dis(compile("first-name + last-name", "_", "eval"))
  0           RESUME                   0

  1           LOAD_NAME                0 (first)
              LOAD_NAME                1 (name)
              BINARY_OP               10 (-)
              LOAD_NAME                2 (last)
              BINARY_OP                0 (+)
              LOAD_NAME                1 (name)
              BINARY_OP               10 (-)
              RETURN_VALUE

Obviously, not all names are valid identifiers as some names may be misinterpreted by the Python interpreter. Instead of fixing the names by trial-and-error, let’s try to learn the exact syntax for identifiers

identifier   ::=  xid_start xid_continue*
...

which is specified in a notation called the Extended Backus-Naur Form (EBNF). Some identifiers called keywords are reserved and therefore not available for programmers to use as variable names. There are also soft keywords that are reserved under specific contexts.

%%hermes --no-context
Explain in one paragraph the notation of the following in pydoc:
identifier ::= xid_start xid_continue*
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)
%%hermes --no-context
What is the motivation for soft keywords in Python? Why not make them hard?
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)
@interact
def identifier_syntax(
    assignment=[
        "a-number = 15",
        "a_number = 15",
        "15 = 15",
        "_15 = 15",
        "del = 15",
        "Del = 15",
        "type = print",
        "print = type",
        "input = print",
    ]
):
    exec(assignment)
    print("Ok.")
Loading...
Solution to Exercise 4
  1. a-number = 15 violates Rule 1 because - is not allowed. - is interpreted as an operator.

  2. 15 = 15 violates Rule 1 because 15 starts with a digit instead of letter or _.

  3. del = 15 violates Rule 2 because del is a keyword.

Solution to Exercise 5 #

Consider

%%hermes --no-context
I want a variable name for storing the total number of students in
class CS1302. Suggest 3 valid Python identifiers following PEP 8 style,
and explain why each is valid.

A good AI response should suggest identifiers like total_students, num_students_cs1302, or cs1302_student_count. Evaluate whether:

  • All suggestions are valid Python identifiers (start with a letter or underscore, contain only alphanumeric characters and underscores).

  • Suggestions follow PEP 8 naming conventions: snake_case for variables, descriptive and readable.

  • The AI explains why each identifier is valid (e.g., does not conflict with Python keywords, uses lowercase with underscores).

Type Conversion

The following program tries to compute the sum of two numbers from user inputs:

num1 = input("Please input an integer: ")
num2 = input("Please input another integer: ")
print(num1, "+", num2, "is equal to", num1 + num2)
Solution to Exercise 6 #

The two numbers are concatenated instead of added together.

input returns user input as a string. E.g., if the user enters 12, the input is

  • not treated as the integer twelve, but rather

  • treated as a string containing two characters, ‘1’ followed by ‘2’.

To confirm this, we can use type to return the data type of an expression.

num1 = input("Please input an integer: ")
print("Your input is", num1, "with type", type(num1))
type(15), type(print), type(print()), type(input), type(type), type(type(type))

(int, builtin_function_or_method, NoneType, method, type, type)

What happens when we add strings together?

"4" + "5" + "6"
'456'

How to fix the bug then?

We can convert a string to an integer using int.

int("4") + int("5") + int("6")
15

We can also convert an integer to a string using str.

str(4) + str(5) + str(6)
'456'
num1 = input("Please input an integer: ")
num2 = input("Please input another integer: ")
# print(num1, '+', num2, 'is equal to', num1 + num2)  # fix this line below
### BEGIN SOLUTION
print(num1, "+", num2, "is equal to", int(num1) + int(num2))
### END SOLUTION
%%hermes --no-context
What is wrong with this code? Explain the error and fix it.
age = input("Enter your age: ")
print("Next year you will be", age + 1)
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

Error Types

In addition to writing code, a programmer spends significant time in debugging code that contains errors. A natural question is:

Can an error be automatically detected by the computer?

You have just seen an example of a logical error, which is due to an error in the logic. The ability to debug or even detect such an error is, unfortunately, beyond Python interpreter’s intelligence.

Let’s see if LLM can debug logical error:

%%hermes --no-context
What is wrong with the following code?
--
num1 = input("Please input a number: ")
num2 = input("Please input another number: ")
print(num1, "+", num2, "is equal to", num1 + num2)
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)

Other kinds of error may be detected automatically by Python. As an example, note that equality == is not equal to assignment =:

print("Assignment:")
"學問" = "學" "問"
  Cell In[32], line 2
    "學問" = "學" "問"
    ^
SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='?

As another example, juxtaposition is not the same as addition +:

print("Juxtaposition:")
3 == 2 1
  Cell In[33], line 2
    3 == 2 1
           ^
SyntaxError: invalid syntax

Python interpreter detects the bug and raises a syntax error.

The following code raises a different kind of error.

print("Add integer to string:")
"4" + "5" + 6  # adding string to integer
Add integer to string:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[34], line 2
      1 print("Add integer to string:")
----> 2 "4" + "5" + 6  # adding string to integer

TypeError: can only concatenate str (not "int") to str

Python is a strongly-and-dynamically-typed language:

  • Dynamically-typed languages check data type only at runtime after translating the code to machine code.

  • Strongly-typed: languages do not force a type conversion to avoid a type error.

To understand what the above actually means, let’s consider how other languages work differently.

C/C++, Java, and Rust are statically-typed languages that check data type during compilation, so the type error above becomes a compile-time error instead of a runtime error.

%%bash
g++ -fsyntax-only 456.cpp
456.cpp: In function ‘int main()’:
456.cpp:5:41: error: no match for ‘operator+’ (operand types are ‘std::__cxx11::basic_string<char>’ and ‘int’)
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                       ~~~~~~~~~~~~~~~~~ ^ ~
      |                                   |       |
      |                                   |       int
      |                                   std::__cxx11::basic_string<char>
456.cpp:5:41: note: there are 14 candidates
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                       ~~~~~~~~~~~~~~~~~~^~~
In file included from /usr/include/c++/15/string:50,
                 from /usr/include/c++/15/bits/locale_classes.h:42,
                 from /usr/include/c++/15/bits/ios_base.h:43,
                 from /usr/include/c++/15/ios:46,
                 from /usr/include/c++/15/bits/ostream.h:43,
                 from /usr/include/c++/15/ostream:42,
                 from /usr/include/c++/15/iostream:43,
                 from 456.cpp:1:
/usr/include/c++/15/bits/stl_iterator.h:629:5: note: candidate 1: ‘template<class _Iterator> constexpr std::reverse_iterator<_Iterator> std::operator+(typename reverse_iterator<_Iterator>::difference_type, const reverse_iterator<_Iterator>&)’
  629 |     operator+(typename reverse_iterator<_Iterator>::difference_type __n,
      |     ^~~~~~~~
/usr/include/c++/15/bits/stl_iterator.h:629:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const std::reverse_iterator<_Iterator>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/stl_iterator.h:1793:5: note: candidate 2: ‘template<class _Iterator> constexpr std::move_iterator<_IteratorL> std::operator+(typename move_iterator<_IteratorL>::difference_type, const move_iterator<_IteratorL>&)’
 1793 |     operator+(typename move_iterator<_Iterator>::difference_type __n,
      |     ^~~~~~~~
/usr/include/c++/15/bits/stl_iterator.h:1793:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const std::move_iterator<_IteratorL>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
In file included from /usr/include/c++/15/string:56:
/usr/include/c++/15/bits/basic_string.h:3838:5: note: candidate 3: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(const __cxx11::basic_string<_CharT, _Traits, _Alloc>&, const __cxx11::basic_string<_CharT, _Traits, _Alloc>&)’
 3838 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3838:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3856:5: note: candidate 4: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(const _CharT*, const __cxx11::basic_string<_CharT, _Traits, _Alloc>&)’
 3856 |     operator+(const _CharT* __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3856:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const _CharT*’ and ‘std::__cxx11::basic_string<char>’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3875:5: note: candidate 5: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(_CharT, const __cxx11::basic_string<_CharT, _Traits, _Alloc>&)’
 3875 |     operator+(_CharT __lhs, const basic_string<_CharT,_Traits,_Alloc>& __rhs)
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3875:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3892:5: note: candidate 6: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(const __cxx11::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*)’
 3892 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3892:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const _CharT*’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3910:5: note: candidate 7: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(const __cxx11::basic_string<_CharT, _Traits, _Alloc>&, _CharT)’
 3910 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs, _CharT __rhs)
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3910:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   deduced conflicting types for parameter ‘_CharT’ (‘char’ and ‘int’)
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3922:5: note: candidate 8: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, const __cxx11::basic_string<_CharT, _Traits, _Alloc>&)’
 3922 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3922:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3929:5: note: candidate 9: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(const __cxx11::basic_string<_CharT, _Traits, _Alloc>&, __cxx11::basic_string<_CharT, _Traits, _Alloc>&&)’
 3929 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3929:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3936:5: note: candidate 10: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, __cxx11::basic_string<_CharT, _Traits, _Alloc>&&)’
 3936 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3936:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3959:5: note: candidate 11: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(const _CharT*, __cxx11::basic_string<_CharT, _Traits, _Alloc>&&)’
 3959 |     operator+(const _CharT* __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3959:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const _CharT*’ and ‘std::__cxx11::basic_string<char>’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3966:5: note: candidate 12: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(_CharT, __cxx11::basic_string<_CharT, _Traits, _Alloc>&&)’
 3966 |     operator+(_CharT __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3966:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3973:5: note: candidate 13: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, const _CharT*)’
 3973 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3973:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   mismatched types ‘const _CharT*’ and ‘int’
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
/usr/include/c++/15/bits/basic_string.h:3980:5: note: candidate 14: ‘template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Alloc> std::operator+(__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, _CharT)’
 3980 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/usr/include/c++/15/bits/basic_string.h:3980:5: note: template argument deduction/substitution failed:
456.cpp:5:43: note:   deduced conflicting types for parameter ‘_CharT’ (‘char’ and ‘int’)
    5 |     std::cout << std::string("4") + "5" + 6 << std::endl;
      |                                           ^
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
Cell In[63], line 1
----> 1 get_ipython().run_cell_magic('bash', '', 'g++ -fsyntax-only 456.cpp\n')

CalledProcessError: Command 'b'g++ -fsyntax-only 456.cpp\n'' returned non-zero exit status 1.
%%bash
javac -d _private/javac-check 456.java
456.java:3: error: bad operand types for binary operator '-'
        System.out.println("4" + "5" - 6);
                                     ^
  first type:  String
  second type: int
1 error
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
Cell In[62], line 1
----> 1 get_ipython().run_cell_magic('bash', '', 'javac -d _private/javac-check 456.java\n')

CalledProcessError: Command 'b'javac -d _private/javac-check 456.java\n'' returned non-zero exit status 1.
%%bash
rustc --emit=metadata 456.rs
error[E0308]: mismatched types
 --> 456.rs:2:46
  |
2 |     println!("{}", String::from("4") + "5" + 6);
  |                                              ^ expected `&str`, found integer

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
Cell In[61], line 1
----> 1 get_ipython().run_cell_magic('bash', '', 'rustc --emit=metadata 456.rs\n')

CalledProcessError: Command 'b'rustc --emit=metadata 456.rs\n'' returned non-zero exit status 1.

On the opposite extreme, the web programming language JavaScript does not raise any error at all:

%%javascript
let x = '4' + '5' + 6;
element.append(x + ' ' + typeof(x));
// no error because 6 is converted to a str implicitly
Loading...
%%javascript
let x = '4' + '5' - 6;
element.append(x + ' ' + typeof(x));
// no error because 4 and 5 are converted to numbers implicitly
Loading...

JavaScript forces a type conversion to make the code run. It is called a weakly-typed language because of this flexibility.

%%javascript
element.append(
    ("b" + "a" +
     + "a" + "a").toUpperCase()
);
Loading...
Solution to Exercise 9 #

See the explanation here.

Maybe AI knows why?

%%hermes --no-context
Why does the following JavaScript return BANANA?
element.append(
    ("b" + "a" +
     + "a" + "a").toUpperCase()
);
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)
%%hermes --no-context
Why `"4"+"5"+6` works for java while `'4'+'5'+'6'` works for C++? 
Is there a rigorously definition of coersion for weakly-typed language that
is different from the above behavior?
Loading...
↻ Session: main (ACP: c6e8a13b-20e…)
Footnotes
  1. The conversion from machine code to assembly code is called disassembly, hence the name dis. BTW, why an interpreted language like Python has a compiler? The interpreter actually compiles the source code to a more compact form called the bytecode that allows the interpreter to run it faster. Indeed, even though Python was originally intended to be an interpreted language, Python 3.13 supports JIT compilation that will compile source code Just In Time to machine code for the first run... Why? See this post.

  2. match and case are recognized as keywords in the context of a match statement, where _ is treated as a wildcard. This is regardless of whether match, case, or _ are used as variables outside this context.

  3. TypeScript is a superset of JavaScript that adds optional static typing and other features to the language. By enforcing stronger typing, TypeScript can detect potential errors at compile-time and improve the overall reliability of your code. Learn more about TypeScript at typescriptlang.org.