"no variable or argument declarations are necessary."

  • Thread starter James A. Donald
  • Start date
M

Mike Meyer

Steven D'Aprano said:
You've gone from thinking about the implementation of the algorithm to
thinking about how to satisfy the requirements of the compiler. As
context switches go, it isn't as big as the edit-compile-make-run
method of testing, but it is still a context switch.

I'm making context switches all the time when programming. I go from
thinking about the problem in terms of the problem, to thinking about
in terms of programming language objects, to thinking about the syntax
for expressing those objects. Adding another one does have a cost -
but it's no big deal.
I don't know whether there are languages that will check everything in
that way. If there aren't, then perhaps there should be. But Python
shouldn't be one of them.

Right. You're doing different things when you program in a language
like Python, vs. Eiffel (which is where I drew most of my checks
from). Each does what it does well - but they don't do the same
things.
Specifying every last detail about the objects making up the space
shuttle is one of the reasons why it costs umpty-bazillion dollars
to build one, and almost as much to maintain it -- and it still has
a safety record worse than most $10,000 cars.

As if a something that's designed to literally blow you off the face
of the earth could reasonably be compared with an internal combustion
engine that never leaves the ground for safety. The shuttle has one of
the best safety records around for vehicles that share it's
purpose. It's doing something that's inherently very dangerous, that
we are still learning how to do. Overengineering is the only way to
get any measure of safety.

<mike
 
D

Donn Cave

Steve Holden said:
Well I hope you aren't suggesting that declaring variables makes it
impossible to forget to initalise them. So I don;t really see the
relevance of this remark, since you simply add an extra run to fix up
the "forgot to declare" problem. After that you get precisely one
runtime error per "forgot to initialize".

It's hard to say what anyone's suggesting, unless some recent
utterance from GvR has hinted at a possible declaration syntax
in future Pythons. Short of that, it's ... a universe of
possibilities, none of them likely enough to be very interesting.

In the functional language approach I'm familiar with, you
introduce a variable into a scope with a bind -

let a = expr in
... do something with a

and initialization is part of the package. Type is usually
inferred. The kicker though is that the variable is never
reassigned. In the ideal case it's essentially an alias for
the initializing expression. That's one possibility we can
probably not find in Python's universe.

Donn Cave, (e-mail address removed)
 
B

Bengt Richter

In the functional language approach I'm familiar with, you
introduce a variable into a scope with a bind -

let a = expr in
... do something with a

and initialization is part of the package. Type is usually
inferred. The kicker though is that the variable is never
reassigned. In the ideal case it's essentially an alias for
the initializing expression. That's one possibility we can
probably not find in Python's universe.
how would you compare that with
lambda a=expr: ... do something (limited to expression) with a
?

Regards,
Bengt Richter
 
D

Donn Cave

how would you compare that with
lambda a=expr: ... do something (limited to expression) with a
?

OK, the limitations of a Python lambda body do have this effect.

But compare programming in a language like that, to programming
with Python lambdas? Maybe it would be like living in a Zen
Monastery, vs. living in your car.

Donn Cave, (e-mail address removed)
 
R

Ron Adam

Antoon said:
Op 2005-10-03 said:
Well I'm a bit getting sick of those references to standard idioms.
There are moments those standard idioms don't work, while the
gist of the OP's remark still stands like:

egold = 0:
while egold < 10:
if test():
ego1d = egold + 1

for item in [x for x in xrange(10) if test()]:

But it isn't about the idioms. It is about the trade-offs. Python allows
you to do things that you can't do in other languages because you
have much more flexibility than is possible with languages that
require you to declare variables before using them. The cost is, some
tiny subset of possible errors will not be caught by the compiler. But
since the compiler can't catch all errors anyway, you need to test for
errors and not rely on the compiler. No compiler will catch this error:

x = 12.0 # feet
# three pages of code
y = 15.0 # metres
# three more pages of code
distance = x + y
if distance < 27:
fire_retro_rockets()

And lo, one multi-billion dollar Mars lander starts braking either too
early or too late. Result: a new crater on Mars, named after the NASA
employee who thought the compiler would catch errors.


Using (unit)tests will not guarantee that your programs is error free.

So if sooner or later a (unit)tested program causes a problem, will you
then argue that we should abondon tests, because tests won't catch
all errors.

Maybe you need to specify what kind of errors you want to catch.
Different types of errors require different approaches.

* Errors that interrupt program execution.

These are Type errors and/or illegal instruction errors such as divide
by zero. Try-excepts and checking attributes where these are possible
to handle them should be used.

* Human 'user' input errors.

Value testing is what is needed for these.

* Programming errors...

Nothing will replace testing here.


I think what you want is optional name and object locking in order to
prevent certain types of errors and increase reliability and dependability.

Name locking - This will allow you to be able to depend that a
specific name refers to a specific object. But that object can still be
modified if it's mutable.

Object locking - This would make a non mutable object from a mutable
object. A function could work here for lists. This probably isn't
possible with many complex objects. Names need to be rebound in many
objects for them to work. I think this may be much harder to do than it
seems.

An example, (but probably not possible to do).

Const = {}
Const['pi'] = 3.1415926535897931

... add more keys/value pairs ...

lockobject Const # prevent object from being changed
lockname Const # prevent name 'Const' from being rebound

... many pages of code ...

print Const['pi'] # dependable result?


Is this the type of control you want?
Would it make your programs more dependable or reliable?

Name locking might be implemented with additional name spaces, but they
would need to be checked prior to other name spaces, so it could slow
everything down.

And there would probably be ways to unlock objects. But maybe that's
not a problem as I think what you want to prevent is erroneous results
due to unintentional name changes or object changes.

I think both of these would have unexpected side effects in many cases,
so their use would be limited.

Cheers,
Ron
 
P

Paul Rubin

Brian Quinlan said:
Have those of you who think that the lack of required declarations in
Python is a huge weakness given any thought to the impact that adding
them would have on the rest of the language? I can't imagine how any
language with required declarations could even remotely resemble
Python.

What's the big deal? Perl has an option for flagging undeclared
variables with warnings ("perl -w") or errors ("use strict") and Perl
docs I've seen advise using at least "perl -w" routinely. Those
didn't have much impact. Python already has a "global" declaration;
how does it de-Pythonize the language if there's also a "local"
declaration and an option to flag any variable that's not declared as
one or the other?

There's been a proposal from none other than GvR to add optional
static declarations to Python:

http://www.artima.com/weblogs/viewpost.jsp?thread=85551
 
M

marduk

What's the big deal? Perl has an option for flagging undeclared
variables with warnings ("perl -w") or errors ("use strict") and Perl
docs I've seen advise using at least "perl -w" routinely. Those
didn't have much impact. Python already has a "global" declaration;
how does it de-Pythonize the language if there's also a "local"
declaration and an option to flag any variable that's not declared as
one or the other?

I would be happy with a "local" option. e.g.

def myfunc():
local spam = ...
local eggs = ...
global juice

breakfast = juice + spam + eggs # raises an exception (undeclared
breakfast)


What I'm *afraid* of is:

def myfunc(MyClass myparam):
int spam = 6
str eggs

# etc

i.e. typed declarations and type checking. This would annoy the heck
out of me.
 
P

Paul Rubin

marduk said:
def myfunc(MyClass myparam):
int spam = 6
str eggs

# etc

i.e. typed declarations and type checking. This would annoy the heck
out of me.

It could be like Lisp, which has optional type declarations. If you
use the type declarations, the compiler can enforce them through
either static analysis or runtime checks, or alternatively to runtime
checks it can generate optimized code that crashes if the data has the
wrong type at runtime. If you don't use the declarations, you get the
usual dynamically typed data.
 
A

Antoon Pardon

Op 2005-10-04 said:
If it happens at runtime, then you can do it without declarations:
they're gone by then.

That depends on how they are implemented. "declarations" can be
executable statements.

It is not about can we do without or not. It is about are they
helpfull or not. Python would be a whole different language
if it never adapted something it could do without.
Come to think of it, most functional languages -
which are the languages that make the heaviest use of closures - don't
require variable declarations.

But AFAIK they don't work like python which makes any variable
that is assigned to in a function, local. Which is a problem
if you want a writable closure.
Not in a dynamic language. Python lets you delete variables at run
time, so the only way to know if a variable exists at a specific
point during the execution of an arbitrary program is to execute the
program to that point.

It is not perfect, that doesn't mean it can't help. How much code
deletes variables.
Only in a few cases. Type inferencing is a well-understood
technology, and will produce code as efficient as a statically type
language in most cases.

I thought it was more than in a few. Without some type information
from the coder, I don't see how you can infer type from library
code.
I have to agree with that. For whether or not a feature should be
included, there should either be a solid reason dealing with the
functionality of the language - meaning you should have a set of use
cases showing what a feature enables in the language that couldn't be
done at all, or could only be done clumsily, without the feature.

I think this is too strict. Decorators would IMO never made it.
The old way to do it, was certainly not clumsy IME.

I think that a feature that could be helpfull in reduction
errors, should be a candidate even if it has no other merrits.
Except declarations don't add functionality to the language. They
effect the programing process.

It would be one way to get writable closures in the language.
That is added functionality.
And we have conflicting claims about
whether that's a good effect or not, all apparently based on nothing
solider than personal experience. Which means the arguments are just
personal preferences.

Whether the good effect is good enough is certainly open for debate.
But the opponents seem to argue that since it is no absolute guarantee,
it is next to useless. Well I can't agree with that kind of argument
and will argue against it.
Antoon, at a guess I'd say that Python is the first time you've
encountered a dynamnic language. Being "horrified" at not having
variable declarations, which is a standard feature of such languages
dating back to the 1950s, is one such indication.

No I'm not horrified at not having variable declarations. I'm in
general very practical with regard to programming, and use what
features a language offers me. However that doesn't stop me from
thinking: Hey if language X would have feature F from language Y,
that could be helpfull.

Now if the developers think such a feature is not important enough
fine, by me. It is however something different if people start
arguing that feature F is totally useless. Now my impression is
that a number of people regard python or at least some aspects
of it as holy and that suggesting that some specific features
could be usefull is considered sacriledge.
Dynamic languages tend to express a much wider range of programming
paradigms than languages that are designed to be statically
compiled. Some of these paradigms do away with - or relegate to the
level of "ugly performance hack" - features that someone only
experienced with something like Pascal would consider
essential. Assignment statements are a good example of that.

I think we should get rid of thinking about a language as
static or dynamic. It is not the language which should determine
a static or dynamic approach, it is the problem you are trying
to solve. And if the coder thinks that a static approach is
best for his problem, why shouldn't he solve it that way.

That a language allows a static approach too, doesn't contradict
that it can work dynamically. Everytime a static feature is
suggested, some dynamic folks react as if the dynamic aspect
of python is in perril.
Given these kinds of differences, prior experience is *not* a valid
reason for thinking that some difference must be wrong. Until you have
experience with the language in question, you can't really decide that
some feature being missing is intolerable. You're in the same position
as the guy who told me that a language without a goto would be
unusable based on his experience with old BASIC, FORTRAN IV and
assembler.

There seems to be some misunderstanding, I don't remember stating that
missing declarations are intolerable, I certainly dont think so. I
wouldn't be programming in python for over five years now if I
thought so. But that doesn't mean having the possibilty to
declare is useless.
 
M

Magnus Lycka

Some people just don't get the simple fact that declarations are
essentially kind of unit test you get for free (almost), and the compiler
is a testing framework for them.

It seems you've missed the entire point of using a dynamically
typed language. It's not just about saving typing time and making
your methods take up fewer lines of code. It's about writing generic
code. Just look at C++ with all that mess with complex templates,
silly casting and dangerous void pointers etc that are needed to
achieve a fraction of the genericity that Python provides with no
effort from the programmer.

With properly written tests, you can be reasonably that the program
does what you want. Type declarations are extremely limited in this
aspect, and they often give programmers a false sense of security.
 
D

Duncan Booth

Paul said:
What's the big deal? Perl has an option for flagging undeclared
variables with warnings ("perl -w") or errors ("use strict") and Perl
docs I've seen advise using at least "perl -w" routinely. Those
didn't have much impact. Python already has a "global" declaration;
how does it de-Pythonize the language if there's also a "local"
declaration and an option to flag any variable that's not declared as
one or the other?

The difference is that perl actually needs 'use strict' to be useful for
anything more than trivial scripts. Without 'use strict' you can reference
any variable name without getting an error. Python takes a stricter
approach to begin with by throwing an exception if you reference an
undefined variable.

This only leaves the 'assigning to a different name than the one we
intended' problem which seems to worry some people here, and as has been
explained in great detail it incurs a cost to anyone reading the code for
what most Python users consider to be a very small benefit.

If you think variable declarations should be required, then you presumably
want that to cover class attributes as well as local and global
variables. After all assigning to 'x.i' when you meant 'x.j' is at least as
bad as assigning to 'i' instead of 'j'. But unless you know the type of
'x', how do you know whether it has attributes 'i' or 'j'? So do we need
type declarations, or perhaps we need a different syntax for 'create a new
attribute' vs 'update an existing attribute', both of which would throw an
exception if used in the wrong situation, and would therefore require lots
of hasattr calls for the cases where we don't care.
 
A

Antoon Pardon

Op 2005-10-04 said:
Maybe you need to specify what kind of errors you want to catch.
Different types of errors require different approaches.

I want to catch all errors of course.

I know that nothing will ever guarantee me this result, but some things
may help in getting close. So if a language provides a feature that can
help, I generally think that is positive. That such a feature won't
solve all problems shouldn't be considered fatal as some counter arguments
seem to suggest.
 
P

Paul Rubin

Duncan Booth said:
If you think variable declarations should be required,

I don't think they should be required. I think there should optional
declarations along with a compiler flag that checks for them if the
user asks for it, like Perl has.
then you presumably want that to cover class attributes as well as
local and global variables. After all assigning to 'x.i' when you
meant 'x.j' is at least as bad as assigning to 'i'

Yes, lots of people mistakenly use __slots__ for exactly that purpose.
Maybe the function they think __slots__ is supposed to implement is a
legitimate one, and having a correct way to do it is a good idea.
But unless you know the type of 'x', how do you know whether it
has attributes 'i' or 'j'?

If the compiler knows (through declarations, type inference, or
whatever) that x is a certain type of class instance, then it knows
what attributes x has.
 
P

Paul Rubin

Magnus Lycka said:
It seems you've missed the entire point of using a dynamically
typed language. It's not just about saving typing time and making
your methods take up fewer lines of code. It's about writing generic
code. Just look at C++ with all that mess with complex templates,
silly casting and dangerous void pointers etc that are needed to
achieve a fraction of the genericity that Python provides with no
effort from the programmer.

So where are the complex templates and dangerous void pointers in ML?
 
M

Magnus Lycka

James said:
What can one do to swiftly detect this type of bug?

Unit tests. In my experience the edit - test cycle in
Python is typically roughly as fast as the edit - compile
cycle in e.g. C++, and much faster than the full edit -
compile - link - test cycle in C++.

You do use automated tests for your programs don't you?
Otherwise I think you are sifting out gnats while you
are are swallowing camels.

There are also lint-like tools such as pylint and
pychecker if you think static tests are useful for you.

Here at Carmen, we've actually skipped the unit test
step, and run functional tests at once, using the
Texttest framework--and that fits well with our type
of apps. See http://texttest.carmen.se/
 
A

Antoon Pardon

Op 2005-10-05 said:
The difference is that perl actually needs 'use strict' to be useful for
anything more than trivial scripts. Without 'use strict' you can reference
any variable name without getting an error. Python takes a stricter
approach to begin with by throwing an exception if you reference an
undefined variable.

This only leaves the 'assigning to a different name than the one we
intended' problem which seems to worry some people here, and as has been
explained in great detail it incurs a cost to anyone reading the code for
what most Python users consider to be a very small benefit.

It also is one possibility to implement writable closures.

One could for instace have a 'declare' have the effect that
if on a more inner scope such a declared variable is (re)bound it
will rebind the declared variable instead of binding a local name.
 
B

Brian Quinlan

Paul said:
Python already has a "global" declaration;

Which is evaluated at runtime, does not require that the actual global
variable be pre-existing, and does not create the global variable if not
actually assigned. I think that is pretty different than your proposal
semantics.
how does it de-Pythonize the language if there's also a "local"
declaration and an option to flag any variable that's not declared as
one or the other?

Your making this feature "optional" contradicts the subject of this
thread i.e. declarations being necessary. But, continuing with your
declaration thought experiment, how are you planning on actually adding
optional useful type declarations to Python e.g. could you please
rewrite this (trivial) snippet using your proposed syntax/semantics?

from xml.dom import *

def do_add(x, y):
return '%s://%s' % (x, y)

def do_something(node):
if node.namespace == XML_NAMESPACE:
return do_add('http://', node.namespace)
elif node.namespace == ...
...


There's been a proposal from none other than GvR to add optional
static declarations to Python:

http://www.artima.com/weblogs/viewpost.jsp?thread=85551

A few points:
1. making it work in a reasonable way is an acknowledged hard problem
2. it will still probably not involve doing type checking at
compile-time
3. it would only generate a warning, not an error

Cheers,
Brian
 
D

Duncan Booth

Antoon said:
It also is one possibility to implement writable closures.

One could for instace have a 'declare' have the effect that
if on a more inner scope such a declared variable is (re)bound it
will rebind the declared variable instead of binding a local name.

That is one possibility, but I think that it would be better to use a
keyword at the point of the assigment to indicate assignment to an outer
scope. This fits with the way 'global' works: you declare at (or near) the
assignment that it is going to a global variable, not in some far away part
of the code, so the global nature of the assignment is clearly visible. The
'global' keyword itself would be much improved if it appeared on the same
line as the assignment rather than as a separate declaration.

e.g. something like:

var1 = 0

def f():
var2 = 0

def g():
outer var2 = 1 # Assign to outer variable
global var1 = 1 # Assign to global
 
P

Paul Rubin

Brian Quinlan said:
Which is evaluated at runtime, does not require that the actual global
variable be pre-existing, and does not create the global variable if
not actually assigned. I think that is pretty different than your
proposal semantics.

Different how?
Your making this feature "optional" contradicts the subject of this
thread i.e. declarations being necessary.

They're necessary if you enable the option.
But, continuing with your declaration thought experiment, how are
you planning on actually adding optional useful type declarations to
Python e.g. could you please rewrite this (trivial) snippet using
your proposed syntax/semantics?

def do_add(x->str, y->str):
return '%s://%s' % (x, y)

def do_something(node->Node):
if node.namespace == XML_NAMESPACE:
return do_add('http://', node.namespace)
elif node.namespace == ...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top