Python and the power of 'first class' everything
itworld.com
itworld.com
There's a whole bunch of statements — simple (assert, pass, del, break, continue, import, raise, …) and compound (if, while, for, with, try) — which definitely don't qualify
How we'd override "pass" boggles my mind. Same for break and continue, and mostly raise (though you have control over the exception hierarchy).
del can be modified to some extent by changing the "del" double-underscore method of the target. import can be modified in several ways, which is how the zipimport is implemented (not an atomic capability). if, while, and try are effectively atomic, but "for" loops can be redefined by defining an iterator, and with is specified entirely in terms of an interface that allows you to affect what it does too.
Personally, I don't think the right way to phrase it is as "everything is first-class in Python", though. I see it as "when the language designer wants to put a capability into the language, like, say, importing from zip files, instead of hard coding it into the interpreter, an interface is coded into the interpreter that anybody can use", which unfortunately I don't have a snappy word on hand for. Looking over the history of Python you can even see this evolving, with the increasing openness of "import" and metaclasses being the most obvious examples.
"Everything is first class" would lead you to something like Lisp macros, which Python eschews. (For better and for worse.) However, I for one would wish more languages would learn the Python lesson above; it's so frustrating to me when I see a language implement something like "import from a different source" but still give you no way to use this new capability yourself. If it's convenient and powerful to you as a language designer, it'll be even more convenient and powerful in the hands of all your users.
I've never changed the meaning of return, but I easily added a new construct called returnIfError. Instead of having to type the following over and over:
possibleError := attemptSomething
if(possibleError, return(possibleError))
I can now type: trySomething returnIfError
The power granted by quick iteration of ideas is almost always worth the performance and compile time analysis trade off for the things that I work on.An expression that does nothing. Putting `''` in a function is equivalent to `pass` in that it lets the parser do its stuff. `pass` could be a builtin defined as `None` and the behavior would be the same as today, without a keyword.
> Same for break and continue
I'm not saying I know how to replace everything (though I'd probably just remove break and continue, they're nice from time to time but not exactly essential), just that there's a lot of stuff which isn't first-class in Python.
> if, while, and try are effectively atomic, but "for" loops can be redefined by defining an iterator, and with is specified entirely in terms of an interface that allows you to affect what it does too.
I don't get what you're trying to say here.
"with" is a special statement, yes, but the specialness is all stuff you can access from a first-class point of view, up to and including dynamically creating a class that implements the "with" behavior you want, then using that with "with". Yes, you can't create your own arbitrary special-purpose statements the way you can in Lisp, but neither is it true that "with" is cast in stone such that you can't do anything with it. Write anything that conforms to the "with" protocol [2] and it'll work.
Also "first class" in the sense that you can program them are . (the attribute retrieval operator) and [] (usually the dict-lookup operator, but it can be rewritten to do anything you like for a given object).
Mind you, I'm not saying that Python is as flexible as Lisp, it clearly isn't. But it does not lead to understanding to say that "with" has no "first-class" aspects to it. It occupies a middle-ground between C and Lisp. Python has chosen this approach with due deliberation. You might still not like it after you understand it, but let us damn it for what it is, not for what it isn't.
[1]: http://docs.python.org/library/stdtypes.html#typeiter
[2]: http://docs.python.org/reference/datamodel.html#with-stateme...
And lisp's got nothing to do with that either.
> You might still not like it after you understand it, but let us damn it for what it is, not for what it isn't.
You… completely missed the point?
> An expression that does nothing. Putting `''` in a function is equivalent to `pass` in that it lets the parser do its stuff. `pass` could be a builtin defined as `None` and the behavior would be the same as today, without a keyword.
The net behaviour would be the same but actually referencing None in the function body increases the refcount of None and immediately decreases it again.
>>> def foo(): pass # no function body, after all
...
>>> def bar(): None # reference to None
...
>>> def frob(): "" # docstring
...
>>> import dis
>>> dis.dis(foo)
1 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
>>> dis.dis(bar) # incref, decref
1 0 LOAD_CONST 0 (None)
3 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
>>> dis.dis(frob) # see "1 (None)" instead of "0 (None)"
1 0 LOAD_CONST 1 (None)
3 RETURN_VALUE
>>> foo.__doc__, frob.__doc__
(None, '')
I admit the difference is merely an academical one but saying pass is not special is not true.These are all escape continuations.
>which unfortunately I don't have a snappy word on hand for
Abstractions?
Python already has first-class anonymous functions (`lambda`), but highly restricted ones.
Whether Python would actually be improved by macros is debatable, though.
interface TypeConstructor<T,V> { T buildType(V value); }
List<TypeConstructor<T,V>>;
or something like this.
The terminology is math-y to the point of exclusiveness because of Haskell's close association with academia* , but there's a point after which it's simpler to make the compiler check than to rewrite the same kinds of tests over and over and over. Type systems are for expressing your requirements in a way that the compiler can do the tests once, at compile time. Computers are good at automating tedious and repetitive work, y'know?
It's too bad most of the people discussing how these things work seem hell-bent on using Greek letters and other insular terminology for everything. Static typing is kind of a wash for smaller projects (I'd just use Lua or Python for something that will only be a few pages of code), but once you start worrying about maintenance or testing changing interfaces between modules, the immediate feedback from a good static type system really comes in handy.
OCaml is a pretty great language, but has some major usability warts and not that much written about it in English. (And Haskell's "avoid success at all costs" motto is...telling.)
If the comment was "But you don't get any type checking" instead of "My language can do this too", then it'd make perfect sense.
And once I arrived at this important realization, all the discussion of 'yay, I am SO dynamic' kind of fell over, because a lot of things reverted to the same principle of interfaces and programming to interfaces.