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 controlsValues¶
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.
Values in Turing Machine
For the Turing Machine, a program that specifies which values to compute is itself a value. The program and the data it manipulates are mingled together into a tape of binary sequence:
How Do Turing Machines Work?
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)
1515# in 'b'inary (base 2)
0b111115# in 'o'ctadecimal (base 8)
0o1715# in he'x'adecimal (base 16)
0xF15All 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
Explain briefly how to redefine the equality operator in Python so that
0 is equal to 1?🌿 Fork/new: main (will create on click)
See Also
In Python, you can’t modify the __eq__ method on the built-in int type (it’s implemented in C), so you can’t make the literal 0 == 1 evaluate to True.
However, you can create a custom integer subclass where it happens:
class WeirdInt(int):
def __eq__(self, other):
if isinstance(other, WeirdInt):
return True # everything equals everything
return super().__eq__(other)
a = WeirdInt(0)
b = WeirdInt(1)
print(a == b) # TrueKey limitation: a == 0 is True, but a == 1 returns False (because a.__eq__(1) falls through to super().__eq__), i.e., the built-in integer comparison.
There are also expressions with integer values but are not integer literals:
4 + 5 + 615pow(2, 4) - 115### 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!How to represent all integers?
Wouldn’t it be nice if there is no limit on how many integers a computer can represent? Since bits can represent at most integers, do we need infinite bits to represent an unbounded number of integers? That would take forever to input an integer into the computer, let alone storing it in finite memory! How about using a variable-length code? See the Kraft-McMillan inequality. An example of variable-length code is UTF-8 encoding for Unicode.
%%hermes
Use a simple analogy to explain in a short paragraph how can a computer
represent all integers using variable-length code?🌿 Fork/new: main (will create on click)
See Also
Think of it like a game of “hot or cold” where you ask yes/no questions to guess a number. To represent small numbers, you need just a few bits—like asking “is it zero?” and stopping immediately if the answer is yes. For larger numbers, you ask more questions: “is the high bit set?”, then “is the next bit set?”, and so on. The trick is using a continuation bit—a prefix that says “keep reading” or “this is the end.” UTF-8 does something similar for text: single-byte characters (common ASCII) get short codes, while rarer characters use multi-byte sequences where each byte except the last has its high bit set as a signal to continue. This way, you can represent any integer: small ones use few bits, and the code simply grows longer as needed.
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
0001f600is the unicode in hexadecimal,grinning faceis the name, and\is called the escape symbol.
Control code
\n and \t are control code that does not represent any symbol.
\ncreates a new line when printing the string.\tcreates a tab to indent the line.
Benefits of allowing single, double, and triple quotes for string literals
By using double quotes, we don’t need to escape the single quote in strings such as “I’m”.
Triple quotes enable a multi-line string literal to include the newline character directly, resulting in a more readable representation of the literal.
Why a string value is often quoted in a computer program? Let’s ask AI:
%%hermes
Say your name.🌿 Fork/new: main (will create on click)
%%hermes
Say "your name".🌿 Fork/new: main (will create on click)
An example is worth a thousand words, but exceptions often exist:
%%hermes
Are there programming languages that do not quote its string? Why?🌿 Fork/new: main (will create on click)
See Also
Several languages don’t require quotes for strings, and the reasons reveal interesting design trade-offs:
Text-as-default languages — In LaTeX, Markdown, HTML, the default content is text. Special syntax (like $...$ for math in LaTeX) marks the non-text parts. This makes sense because these languages are primarily about documents, where code is the exception.
Shell scripting — In bash, unquoted hello is treated as a string (a word that may undergo expansion/splitting). It works because the shell’s grammar distinguishes command positions from data positions by context.
Prolog — Unquoted hello is an atom (a symbolic constant), while "hello" is actually a list of character codes. The language distinguishes symbolic identifiers from character sequences.
Why Python quotes strings — The core ambiguity: in hello, is it a variable name or the string "hello"? Without quotes, the parser can’t tell. Quoting is the simplest way to disambiguate.
The notebook’s point connects here: quoting strings in programs separates data (the string value) from code (identifiers, keywords, operators). In document languages, that distinction is flipped — text is data by default, and markup is the annotation.
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_methodWe can also use the contextual help by placing the cursor over a function name and
click the menu item
HelpShow Contextual Helporpress 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 SOLUTIONNote: you may need to restart the kernel to use updated packages.
____ ___ ____ __ ___ ___ ____ ____ _ _____ ___ ____
|___ \ / _ \ |___ \ / /_ / _ \ / _ \ / ___|/ ___| / ||___ / / _ \ |___ \
__) || | | | __) || '_ \ | | | || (_) || | \___ \ | | |_ \ | | | | __) |
/ __/ | |_| | / __/ | (_) || |_| | \__, || |___ ___) || | ___) || |_| | / __/
|_____| \___/ |_____| \___/ \___/ /_/ \____||____/ |_||____/ \___/ |_____|
___ _ _ ____ ____ _
|_ _| _ __ | |_ _ __ ___ | |_ ___ / ___| ___ _ __ ___ _ __ | _ \ _ __ ___ __ _ _ __ ___ ( ) __ _
| | | '_ \ | __|| '__| / _ \ | __| / _ \ | | / _ \ | '_ ` _ \ | '_ \ | |_) || '__| / _ \ / _` || '_ ` _ \ |/ / _` |
| | | | | || |_ | | | (_) | | |_ | (_) | | |___ | (_) || | | | | || |_) | | __/ | | | (_) || (_| || | | | | | | (_| |
|___||_| |_| \__||_| \___/ \__| \___/ \____| \___/ |_| |_| |_|| .__/ |_| |_| \___/ \__, ||_| |_| |_| \__, |
|_| |___/ |___/
Check if AI can understand your message, such as the ones below:
%%hermes
Explain what you see in the following:
(ง •̀_•́)ง
╰(●’◡’●)╮
(..•˘_˘•..)
(づ ̄ 3 ̄)づ🌿 Fork/new: main (will create on click)
See Also
These are kaomoji (Japanese emoticons) — visual expressions built entirely from Unicode characters arranged to form faces and gestures. They’re a perfect example of string values as sequences of characters:
(ง •̀_•́)ง — “Flexing muscles” / “Ready to fight” — raised fists
╰(●’◡’●)╮ — “Shrug” / happy open-arms gesture
(..•˘_˘•..) — Sleepy / tired face
(づ ̄ 3 ̄)づ — Hugging gesture
Each one is a string value composed of Unicode characters from different blocks — parentheses, Latin letters, special symbols, and decorative characters. They demonstrate that strings aren’t just letters and numbers; they’re arbitrary sequences of code points that, when rendered by a font, form visual meaning.
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
inputmethod 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
enterafter typing a string.
print("My name is", print("Python"))Python
My name is None
Solution to Exercise 3 #
Unlike
input, the functionprintdoes not return the string it is trying to print. Printing a string is, therefore, different from returning a string.printactually returns aNoneobject that gets printed asNone.
%%hermes
Explain whether the Python print function returns the value it prints.🌿 Fork/new: main (will create on click)
See Also
No — print() returns None. It’s a procedure (side-effect), not a function that computes a value.
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 = 15What does the above code mean?
is equal to 15?
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 + 1In the second assignment, does it mean:
is equal to +1?
is defined to be +1?
If we say yes to the above questions, the value of should be . (Why?)
%%hermes
What is the solution to $x+1=x$ for $x$ in the extended real line?🌿 Fork/new: main (will create on click)
See Also
In the extended real line , both and are solutions. For any finite real number , subtracting from both sides gives (impossible). But by the arithmetic conventions of the extended reals: and .
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 RESUME 0
1 LOAD_NAME 0 (x)
LOAD_SMALL_INT 1
BINARY_OP 0 (+)
STORE_NAME 0 (x)
LOAD_CONST 1 (None)
RETURN_VALUE
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.
%%pytutor
x = y = 1+1j
del x
xCaution
You will learn later in the course that deleting a variable does not necessarily delete its value. In the above example, the value 1+1j continues to exist after x is deleted.
Are there constants in Python?
As the concepts of variables and values in programming are analogous to those in mathematics. Is there a programming counterpart for mathematical constants such as ? In Python:
There is a list of constants.
There are immutable objects.
There is a math module defining mathematical constants like
pi.
%%hermes
How would you define constants in Python? Are literals also constants?🌿 Fork/new: main (will create on click)
See Also
Constants in Python:
Python has no built-in
constkeyword — there’s no language-level enforcementConvention:
ALL_CAPSnames (e.g.,MAX_SIZE = 100) signal intentType-checker support:
typing.Finalprevents reassignment at static analysis time
Are literals constants? Not in the same sense. A literal (42, "hello") is a value written directly in code. A constant is a named variable intended not to change. Literals are inherently fixed (you can’t modify 42), but they aren’t “constants” — they’re values. Constants are names bound to values that you promise not to rebind.
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:
%%pytutor
def name():
return first.name + last.name
first.name = "John"
last.name = "Smith"
print(name())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
Explain in one paragraph the notation of the following in pydoc:
identifier ::= xid_start xid_continue*See Also
This is ABNF (Augmented Backus-Naur Form) notation. The ::= means “is defined as.” It says an identifier must start with one character from xid_start (letters, _, etc.) followed by zero or more characters (*) from xid_continue (letters, digits, _). So x is valid (one start char, zero continues), but 3x is not (digits aren’t in xid_start).
%%hermes
What is the motivation for soft keywords in Python? Why not make them hard?See Also
Backward compatibility. Making a word a hard keyword breaks all existing code that uses it as an identifier (variable names, function names, etc.). Soft keywords are only special in their specific context (match/case only at the start of a statement, type only in type alias positions, _ only in pattern matching), so existing code like match = "winner" or case = 1 continues to work unchanged.
@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.")Solution to Exercise 4
a-number = 15violates Rule 1 because-is not allowed.-is interpreted as an operator.15 = 15violates Rule 1 because15starts with a digit instead of letter or _.del = 15violates Rule 2 becausedelis a keyword.
Python Enhancement Proposals
To help make the code more readable, programmers follow additional style guides such as Python Enhancement Proposals (PEP) 8:
Function names should be lowercase, with words separated by underscores as necessary to improve readability.
Variable names follow the same convention as function names.
Solution to Exercise 5 #
Consider
%%hermes
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_casefor 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")15We 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
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)🌿 Fork/new: main (will create on click)
See Also
input() returns a string, so age + 1 tries to concatenate a string with an integer — which raises a TypeError.
Fix: convert the input to an integer first:
age = int(input("Enter your age: "))
print("Next year you will be", age + 1)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
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)🌿 Fork/new: main (will create on click)
See Also
Same issue — input() returns strings, so num1 + num2 performs string concatenation, not numeric addition. If you enter 3 and 4, it prints 3 + 4 is equal to 34 instead of 7.
Fix: convert to numbers before adding:
num1 = float(input("Please input a number: "))
num2 = float(input("Please input another number: "))
print(num1, "+", num2, "is equal to", num1 + num2)(Using float instead of int handles decimals as well.)
Can an LLM detect logical errors?
The response depends heavily on the context. For example, suppose the above program intended to:
Add two binary numbers from user input.
Typically, numbers refer to real numbers, so LLM likely will get it wrong without knowing the context. Refining questions based on the LLM’s responses can yield more meaningful answers. Essentially, we should learn to ask questions properly with context to gain knowledge.
Other kinds of error may be detected automatically by Python. As an example, note that equality == is not equal to assignment =:
%%pytutor
print("Assignment:")
"學問" = "學" "問"As another example, juxtaposition is not the same as addition +:
%%pytutor
print("Juxtaposition:")
3 == 2 1Python interpreter detects the bug and raises a syntax error.
Why Syntax error can be detected automatically?
Note that the print statement is not executed. Why?
The Python interpreter can detect a syntax error even before executing the code because the interpreter simply fails to translate the code to lower-level executable code.
The following code raises a different kind of error.
%%pytutor
print("Add integer to string:")
"4" + "5" + 6 # adding string to integerWhy Python throws a TypeError when evaluating '4' + '5' + 6?
'4' + '5' + 6?There is no implementation of + operation on a value of type str and a value of type int.
Unlike the syntax error, the Python interpreter can only detect a type error at runtime (when executing the code.)
Hence, such an error is called a runtime error.
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.cpp456.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[49], 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.java456.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[50], 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.rserror[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[51], 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%%javascript
let x = '4' + '5' - 6;
element.append(x + ' ' + typeof(x));
// no error because 4 and 5 are converted to numbers implicitlyJavaScript forces a type conversion to make the code run. It is called a weakly-typed language because of this flexibility.
Why not make Python a more flexible weakly-typed language by automatic type conversion?
While weakly-typed languages may seem more robust, they can potentially lead to more logical errors. JavaScript, despite its popularity, is known for its tricky behavior, as demonstrated in wtfjs. To improve readability and avoid logical errors, it is recommended to use the strongly-typed language TypeScript.[3]
%%javascript
element.append(
("b" + "a" +
+ "a" + "a").toUpperCase()
);Solution to Exercise 9 #
See the explanation here.
Maybe AI knows why?
%%hermes
Why does the following JavaScript return BANANA?
element.append(
("b" + "a" +
+ "a" + "a").toUpperCase()
);See Also
It’s a classic JavaScript pun! Here’s the breakdown:
"b" + "a" → "ba"
Then + + "a": the second + is the unary plus operator, which converts its operand to a number. +"a" evaluates to NaN.
So "ba" + NaN → "baNaN" (strings concatenate with NaN), and adding the final "a" gives "baNaNa".
.toUpperCase() turns it into "BANANA". 🍌
%%hermes
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?See Also
Java — "4"+"5"+6 works because:
+with at least oneStringoperand does string concatenationNon-strings are implicitly converted via
String.valueOf()→ result"456"
C++ — '4'+'5'+'6' works because:
Single quotes are
charliterals, which are integral types (ASCII 52, 53, 54)+performs numeric addition → 159
Rigorous coercion definitions? Yes. The ECMAScript specification (JavaScript) defines coercion as precise abstract operations: ToNumber, ToString, ToPrimitive, etc. For example, + uses the abstract operation Add with explicit rules (if either operand is a string, convert both to strings; otherwise to numbers). So JavaScript’s coercion is fully specified—it’s just weak, not undefined.
The key distinction: weak vs strong typing is about how permissive the rules are, not whether they exist. A weakly-typed language can have a rigorous spec that permits more implicit conversions; a strongly-typed one (like Python) has equally rigorous rules that reject implicit coercion between types.
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.matchandcaseare recognized as keywords in the context of amatchstatement, where_is treated as a wildcard. This is regardless of whethermatch,case, or_are used as variables outside this context.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.