like everyone else, someday i dream of writing a programming language (even though, right now, i know next to nothing about the subject). i'll call it jasper (notes specifically on Jasper). this page started aspiring to become a list of every (language-supported) programming construct that i've ever heard of, but quickly degenerated into a list of language features, and then into a list of language design notes-to-self of all sorts.
idea from Alan Kay in an interview (http://portal.acm.org/ft_gateway.cfm?id=1039523&type=html&coll=ACM&dl=ACM&CFID=54537199&CFTOKEN=59179419): trying to get x-platform compatibility by writing specs and writing a checker never works. the way to do it is to write the compiler in the new language itself. then it compiles itself to C.
also: " In the 60s, one of the primary goals of the computer science community was to arrive at an extensible language. As far as I know, only three ever actually worked, and the first Smalltalk was one of those three. Another very interesting one was done by Ned Irons, who invented the term syntax-directed compiler and did one of the first ones in the 60s. He did a wonderful extensible language called Imp. "
(he doesn't say what the third one is)
" One of the things that people realized from these extensible languages is that there is the unfortunate difficulty of making the meta-system easy to use. Smalltalk-72 was actually used by children. Youre always extending the language without realizing it when you are making ordinary classes. The result of this was that you didnt have to go into a more esoteric place like a compiler compiler %G— %@Yacc or something like that %G— %@to add some extension to the language."
i don't understand this but maybe its important:
" One of my favorite old languages is one called Lucid by Ed Ashcroft. It was a beautiful idea. He said, Hey, look, we can regard a variable as a stream, as some sort of ordered thing of its values and time, and use Christopher Stracheys idea that everything is wonderful about tail recursion and Lisp, except what it looks like. When he looked at Lisp, he had a great insight: which was that tail-recursive loops and Lisp are so clean because youre generating the right-hand side of all the assignment statements before you do any rebinding. So youre automatically forced to use only old values. You cannot rebind, so there are no race conditions on anything.
You just write down all of those things, and then when you do the tail recursion, you rebind all of those variables with these new values. Strachey said, I can write that down like a sequential program, as a bunch of simultaneous assignment statements, and a loop that makes it easier to think of. Thats basically what Lucid did %G— %@there is no reason that you have to think recursively for things that are basically iteration, and you can make these iterations as clean as a functional language if you have a better theory about what values are.
"
http://www.uidesign.net/2000/interviews/cooper1.html
Alan Cooper:
"The point is that, if you are a Visual Designer, or if you are an HCI Professional, or even programmers you tend to approach things from the point of view of saying, what are the technological tools at your disposal. You say, Oh, I have a relational database. Therefore, I can issue a query and I can get back, in a batch mode, a solution set of a reduced number of choices.
You might have a real world situation where you have someone who walks into a library and searches based on a Dewey Decimal Categorization System number and then wants to see a list of related books. The query system fundamentally disallows this."
" Why can't I logically group things? I can categorize things. I can say, here is a name that belongs in my list of business names, here's another which belongs in my list of personal names, but I have lots of names that need to be in both lists. I"
"For example, using any typical operating system e.g. Linux, NT, MacOS?, when you create a chunk of data, you have to put it in a named data block, some file. You then have to put that in some place, in a positionally notated storage hierarchy. So you have to choose a name, and you have to choose and specify a place, a node in a tree. When you want that information back again, you have to remember the name that you gave it and you have to remember the place that you stored it. Then you go to that place, remembering the name, and there it is. You can retrieve that data. It's very logical and it's very appropriate but this is a model which is designed for computers.
The Problem is that humans are really bad at remembering names and places. With that kind of specificity, especially in a recursive hierarchy, where the nodes are exactly alike regardless of what level they are. Of course, computers happen to be really good at remembering stuff like that. However, the computer doesn't give me any help in remembering. The computer delegates that [remembering] job to the human. That's because the guys who invented operating systems.... that sort method comes from Kernighan and Plauger, from Unix. If you're a computer program remembering a simple file name in a directory is a trivial task. They [ the operating system inventors] just handed that task out to the human user.
That is not a simple or trivial task for humans. No one has ever gone back in and said, "Hmmm. Is this appropriate?" I talk a lot about this in my first book, "About Face"."
"If you have a modern cell phone then you know that you have probably recorded into the memory, 50 or 100 phone numbers, and you probably have a speed dial of 8 or 10 numbers which you dial frequently. If you think about the number of times that you key in from scratch, a phone number - area code, prefix, number - is maybe 1 in 10. The other 9 times, you use numbers which the phone has already remembered. Yet the physical interface of the phone which is presented is highly tilted towards dialing those numbers from scratch.
You need a functional overlay and you have to switch into a meta-mode in order to dial up numbers which the phone has already memorized and you regularly dial. This is because we don't think from a Goal-Directed(R) point of view. We don't look at the way people actually do things. Instead we look at the technology and we say, "The way you telephone someone is by typing in a number." Then we say, "Hey we could make this more convenient by having it remember numbers".
Why not instead say, "People always call, the people that they always call". Then you could have something simple like a knob on the top of telephone which just spins through the top 20 people that you call all the time. And by the way, for the rare occasions when you do have to call a strange number, then you turn it over and open up the back and there are the numbers [keys]. "
"detect" control structure:
A = [9,8,7,6,1,4,3,2,5] i = -1 # Left index j = len(A)-1 # Right index v = A[-1] # Pivot
detect 'Partition done': detect 'Move element j down': i = i+1 if i==j: 'Partition done' if A[i] > v: A[j] = A[i] 'Move element j down' detect 'Move element i up': j = j-1 if j==i: 'Partition done' if A[j] < v: A[i] = A[j] 'Move element i up'
A[j] = v
print A
(from http://www.idi.ntnu.no/~mlh/python/partition.py and "Event-Driven Control Statements", BIT 15, pp. 229-275)
tuples: should be able to return multiple values
vectorization, like octave does, is nice
think about how the web/internet changes things.
a "get" primitive, to get information from some information source (file/ftp/web)?
serialization primitives
distributed computing primitives? remote method invocation? distributed objects?
GUI primitives (seems uneeded)
also, paralled computing primitives (synch/monitor tokens, etc)
text processing primitives, like Perl's RE handling (I don't think Python makes this concise enough)
i think a good way to develop a language is to have a number of test programs, and find the shortest, clearest way to express these programs, then make a language that can understand that
http://merd.sourceforge.net/pixel/language-study/scripting-language/
should have set theory primitives, matrix construction primitives, sequence construction primitives, etc. i.e. the set "union{i\inN} A_i" should be constructible (and lazily evaluated)
generators & conditionals from Icon: http://www.cs.arizona.edu/icon/docs/ipd266.htm
Paul Graham's list of cool things about LISP:
It was natural to have this distinction in Fortran I because you could not nest statements. And so while you needed expressions for math to work, there was no point in making anything else return a value, because there could not be anything waiting for it.
This limitation went away with the arrival of block-structured languages, but by then it was too late. The distinction between expressions and statements was entrenched. It spread from Fortran into Algol and then to both their descendants.
Running code at read-time lets users reprogram Lisp's syntax; running code at compile-time is the basis of macros; compiling at runtime is the basis of Lisp's use as an extension language in programs like Emacs; and reading at runtime enables programs to communicate using s-expressions, an idea recently reinvented as XML.
---
(i'm particularly interested in #9; i sorta want Python, but with #9; thinking about why you can't easily add this on, it seems you need #8 for that to work; but also, i guess you need to design the core of the language with the need to write a compiler for it in itself succinctly)
btw, can you have a program that looks like a graph instead of a tree? might be good for massive parallelism
btw, i think programming languages of the future MUST support massive parallelism; we need to be able to use "active data structures" described in The Connection Machine when computers become capable of it.
might also be interesting to check out http://www.norvig.com/python-lisp.html
http://phaseit.net/claird/comp.lang.python/python_introspection.html:
Cameron Laird's personal notes on introspection in Python In Usenet article <199803021544.KAA17164@eric.CNRI.Reston.Va.US>, Guido followed up
Good question. Python has a lot of introspection features but some of them are a bit haphazard and others are perhaps less-than-optimally documented.
(The key ones, of course, are so simple that you don't even think about them -- __dict__, __class__, __bases__, __name__, __file__, as well as locals(), globals(), vars(), dir(), type(), isinstance(), issubclass(), not to mention sys.modules.)
I've rarely felt the need to extract signatures from functions, but I can see that such a need exists in others.
Perhaps we can create a list of needed introspection features?
That's what this page is: "a list of needed introspection features". The initial question had to do with a function which reports a method's signature. Fred L. Drake, Jr., pointed out a number of features beyond those Guido mentions above, including:
You could try:
try:
version = func.func_globals['__version__']
except KeyError:
version = None
The value of __version__ should be set if the author will make sure
the module will not be released without updating the number. One way
to do this under CVS or RCS would be:
__version__ = "$Revision$"
Other revision control systems may support similar constructs.Other possibilities that come to mind quickly (disclaimer: I'm writing this list in creative mode; it's likely that several of them are already implemented, and I just haven't noticed it yet):
exception handling: should allow functions to "throw" exceptions like java, but then, to prevent each higher function from having to throw more and more exceptions, should provide a facility for caller to say, "redefine any exceptions that were not thrown by the immediate child to "ChildException? (where "ChildException?" is something they specify), so that they can be caught all at once (or maybe just, "refine all exceptions thrown by this child to ChildException?