Python doesn't have implicit declaration. The first occurrence of the assignment syntax declares the variable and binds it to a value.
Proof that Python doesn't have implicit declaration:
>>> foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
Pyhon's design sin is that it fails to distinguish the binding of a variable from assignment. The programmer cannot locally (i.e. just in that statement alone) express "I expect this statement to be freshly creating a variable, introducing it into the scope, with value 42" and "I expect to be assigning value 42 to a variable which already exists in the scope (or else this should be diagnosed)".
An example of a language actually without declaration is Awk. This helps one-liners be very terse, but hinders large programs.
Proof that awk has implicit declaration in contrast to Python:
$ awk 'BEGIN { print foo }'
$
No errors. The shell has implicit declaration:
$ echo $foo
You turn it off in serious scripts with "set -u" to have it diagnosed.
If Mathematica couldn't simplify formulas over variables that are not instantiated, what good would it be? That's an important job of a computer algebra system.
Yes being a CAS and a general purpose language is at odds. I guess there's two paths
a) use sigils to signal that some variable should be treated as an abstract values for CAS purposes. like, :x + :x rather than x + x (or.. use sigils to signal that a variable is "normal", like $x is a normal variable and x + x is CAS stuff)
b) declare CAS variables as such before using them. like with a "var" keyword or something. optionally, declare normal variables, but with a different keyword
Note that formal math always look like "b)" (we declare our variables before using them), it's informal math that looks what Mathematica is doing
> Python doesn't have implicit declaration. The first occurrence of the assignment syntax declares the variable and binds it to a value.
That's exactly what he means by "implicit declaration" though - he even calls out Python as an example.
Python does have implicit declaration, it is just slightly more limited than languages like Bash and CMake - it only implicitly declares variables when you write to them, not when you read them.
Anyway, regardless of the semantics I think we all agree that all forms of implicit variable declaration are a bad idea.
Betz should fix his terminology to align with the industry.
There is nothing implicit about x = 42 in Python. You wrote it explicitly.
The language is not pretending that you invisibly defined x somewhere at the top and are now assigning it.
The most familiar "implicit declaration" to everyone is the feature in traditional C (that any good C compiler warns about and was banished in C++ early). Like that you can call a function without declaring it:
puts("Hello"); /* no <stdio.h> included */
The compiler looks at the argument types and deduces a declaration. The return type is assumed to be int, and since the "Hello" expression decays to char * type, the implicit declaration is int puts(char *).
Python actually doesn't have declarations at all (except when we consider the new typing features).
When we introduce something into a scope without giving any attributes about it like type, that's a definition. A declaration is something which makes facts known about an identifier: like whether it is a constant, does it have a type, and such. It doesn't necessarily make it exist.
In Lisp declarations can be added about an existing identifier:
(let ((x 3)) ;; definition of x
(declare (type (integer x))) ;; declaration about x
...)
In languages focused on static type, definitions declare. E.g. in C, all definitions (other than of macros) are declarations; not all declarations are definitions.
In Python, a variable must be visibly defined before it is used, quite clearly; it doesn't have implicit definition. Untyped Python has no declarations.
> Like that you can call a function without declaring it:
That's exactly the same as your Python example!! "There's nothing implicit about `puts("Hello");`. You wrote it explicitly."
> When we introduce something into a scope without giving any attributes about it like type, that's a definition. A declaration is something which makes facts known about an identifier: like whether it is a constant, does it have a type, and such. It doesn't necessarily make it exist.
No. A declaration can only declare that a variable exists. Consider this in Javascript:
let foo;
Not "having" declarations and declarations being implicit are exactly the same thing. You're getting tripped up over your language.
> A declaration can only declare that a variable exists.
Yes; that's the only correct thing in your comment.
A declaration can declare that a variable exists, and nothing more, which is useful in some language that has a strict rule that variables must have been indicated as existing before they can be used.
If a declaration causes the variable to exist, then it's a definition.
However, about that specific example, "let foo;" in Javascript is actually a definition. It causes foo to exist in the scope where it appears, with a value of undefined.
> Pyhon's design sin is that it fails to distinguish the binding of a variable from assignment. The programmer cannot locally (i.e. just in that statement alone) express "I expect this statement to be freshly creating a variable, introducing it into the scope, with value 42" and "I expect to be assigning value 42 to a variable which already exists in the scope (or else this should be diagnosed)".
I'm not entirely sure this is a bad thing? I'm learning Go right now, and I'm encountering plenty of code like:
err := DoFoo()
if err != nil ....
err = DoBar()
if err != nil ....
The problem with that is that if you remove the DoFoo line you have to change the DoBar line, even though nothing's really changed there. An (albeit small) waste of time, an extra thing to think about which has nothing to do with the problem you're solving, more lines to review in the PR, and more chance of merge conflicts later.
You could bind the variable each time, if that is allowed:
err := DoFoo();
if err != nil ...
err := DoBar()
if err != nil ...
DoFoo and DoBar are different functions; their error return might not even be the same type.
If mixed declarations and statements are not supported:
{
err := DoFoo();
if err != nil ...
}
{
err := DoBar()
if err != nil ...
}
this is what I do in C to reduce the scope of variables, and it has the benefit over
the former example in that we delimit where the scope begins and ends. We know that
after the closing brace, nothing can be referencing that err variable.
(I'm not a fan of mixed decls and statements).
Modern languages should support binding a variable in if:
if (err := DoFoo()) {
// err scoped here
}
My first example would be "bad" according to David Betz because it perpetrates shadowing.
Proof that Python doesn't have implicit declaration:
Pyhon's design sin is that it fails to distinguish the binding of a variable from assignment. The programmer cannot locally (i.e. just in that statement alone) express "I expect this statement to be freshly creating a variable, introducing it into the scope, with value 42" and "I expect to be assigning value 42 to a variable which already exists in the scope (or else this should be diagnosed)".An example of a language actually without declaration is Awk. This helps one-liners be very terse, but hinders large programs.
Proof that awk has implicit declaration in contrast to Python:
No errors. The shell has implicit declaration: You turn it off in serious scripts with "set -u" to have it diagnosed.