If you are interested in a cool game and not at all in computer science, then skip to the end right now. Otherwise eat a banana.
Since you don't have enough printer ink anymore, you should start programming in Babedepupi!
Babedepupi ist a great language in the sense that it doesn't have keywords. That's good, since you don't like keywords. They are stupid and ugly.
It is an object oriented language like Smalltalk or Schemetalk and not like Java or Eiffel.
But let's take a look at how it looks, looking at us, a simple arithmetic operation:
1 + 2
Here '+' is a message passed to the object '1' with the argument '2', returning a new object ('3'). So nothing new or special. What about parentheses? Since no non-white-space character is allowed, we have to do it differently. The expression '2 * (1 + 3)' would translate to:
2 * 1 + 3
As '*' expects one argument, it would consume the '1' and we would lose our parenthesis. So we have to delay the multiplication and we do that with a double space (did you notice? You should buy new glasses). In this example * waits for the rest to execute and then consumes the result.
A more comple exa8mple?
(3 * 4 - 8 * 9) / 2
translates to 3 * 4 + 8 * 9 / 2
It will be executed as follows: first 3 * 4 is executed, since there is no delay. Then a delay occurs, so '+' is delayed and 8 * 9 is executed (as there is no delay after 8 *). After that we get a delay, this time not after a message but after an object. This means that the last delay is resolved, the one after '-'. Finally we end up with / 2 and the result is given.
Now, how are classes defined, let's implement a Boolean class.
Boolean
then block end
System print "Not my responsibility, muaha!"
then thenBlock else elseBlock end
System print "Not my responsibility either!"
True Boolean
then block end
block execute
then thenBlock else elseBlock end
thenBlock execute
False Boolean
then block end
then thenBlock else elseBlock end
elseBlock execute
So we first define Boolean and two methods which should be implemented by inheriting classes. It helps us to define the if then and the if then else. The then else block is special. 'else' is not an argument and belongs to the method definition (note the two spaces). True and False are implemented straightforwardly.
An easy example is:
0 = 1 then
System print "0=1!"
end
A block is written with an indendation. The first line holds all the block variables (none here). After this line, still indendated, we will have the commands of the block.
Similarly we can write:
block =
System print "I am a block, LOL"
Now we will look at how the work in action. We will use a Fibonacci class.
Fibonacci
fib n
n = 0 then
fib = 0
else
n = 1 then
fib = 1
else
fib = fib n - 1 + fib n - 2
end
end
Now you may get confused by the '=' which is used on one hand as equality check like in 'n = 0' and on the other hand as assignment 'fib = 1'. '0' works as equality, iff there is no message send after it, which belongs to Boolean. Finally we find the 'fib = ' statement. The name of the method is always the result variable (like in Pascal). Alternatively it could work like in C/Java and directly jump out of the method.
How about a more complex class, for instance a linked list?
LinkedList
new
first = Container new
last = first
add item
last nextItem item
last = Container new item item
removeAt i
at i nextItem at i nextItem nextItem
[ i ]
[ = at i
at i
at = atRec i first
atRec i current
i = 0 then
atRec = current
else
atRec = atRec i - 1 current
end
Container
item item
data = item
nextItem container
next = container
Yeah, that's all for now. It's obvious that Babedepupi still has flaws, just wanted to write it down for the afterworld.
If you read till here, you are brave indeed. And you'll get a cake (if you didn't see it already): BACK THROUGH TIME!"
That's all folks, next time a drawing again? Who knows? Who? Yeah you there, in the back? No, I don't want your Bible, thank you very much.
PS: No Scheme/LISP-trolling please.
4 Kommentare:
First, I like a big part of the syntax. Especially "[ i ] [ = at i" is genius :)
Then the things I don't like:
1) While you can possibly delay until infinity and encode all possible combinations of "implicit parentheses", I definitely don't think it's a good replacement for parentheses. It can't get much more readable then "((3 + 4) / (5 * 3) / (3 + 2)) ** 10". All those extra spaces will make it horrible to write this kind of expression.
2) You actually -do- have a keyword, namely the name of the method itself. And as far as I can see, it's not even first-class (at least, you didn't specify it to be). I don't even see the reason to do this.
If you look at scheme (troll troll), there the last expression of the list is the return-value. And that works. Now there are situations where "return" "keywords" are useful, I know. But why build in a keyword which is available from within one given scope? Even if you allow non-local returns from blocks originating from your scope, like in Smalltalk, this is limiting. If you look at scheme, thanks to continuations and their optimized form, escape continuations, you have all that power in your hands.
(method () 3) is a method which returns 3, since it's the last expression in the list.
(method () (call/ec (lambda (^) 1 (^ 2) 3))) is a method in which you call call/ec with a lambda with 1 argument, ^. call/ec puts a "marker on the stack" for you and wraps a special construct which can jump back to that marker. This special construct is passed to the lambda which call/ec gets as an argument. This special construct can behave like the return in smalltalk, which is why I named it ^ here. Now this construct looks like a function; and when you call it; it "replaces" the call to call/ec with the value you pass. In the example, call/ec gets "replaced" by 2. Since call/ec is the last expression of the method, 2 will be what is actually returned.
Even better! This construct is -not- a keyword, and thus can be passed around to anyone to do a non-local return.
(if you look closely at it, the lambda is actually by itself a function which will do the non-local return of call/ec of which it received the return construct :))
3) You didn't specify semantics for numbers and for example = on numbers. I -hope- numbers are evaluated "the smalltalk way" and will be linked to an extensible class?
4) The newlines after block headers. Horrible! I understand why, and that is why I just saw the next thing:
5) How do you see the diff between instance variables and temporaries of a method? And in case you have a solution, doesn't this apply for 4 too? (so I guess you don't have one :))
6) Printer ink friendly languages should all be DSLs written in whitespace
or piet just to equally distribute color usage, so your cartridge is not only half-used.
Enough comments for now, I'll save some for the next official specification release of the language :)
cheers,
tOon
It's amazing that this language became already so popular that even the family guy knows it...
However, I'm not sure if I like a language in which
(3 * 4 - 8 * 9) / 2
translates to
3 * 4 + 8 * 9 / 2;
I would at least expect that the operators remain the same... ;)
Are you aware of the shunting yard algorithm by Dijkstra? It turn any infix notation into a stack based computation.
BTW, over 14 internets to you for linking the amazing time travel game! Just bought the game!! It rocks!!! (As I am writing this from the future, please honor that I spend chrono on commenting your post.)
Kommentar veröffentlichen