Discussions in support of the LOLCODE.com wiki
You are not logged in.
I made the proposal, heavily based on perl.
The goal is for foreach to be natural and I also felt unlike other proposals that it definitly should include the ability to do
IM IN YR WIKIPEDIA EATIN UR ARTICLES
I am a noob here, so please don't be offended if I trampled on someone or overlooked something already in existence. And yes there are some differences I put in.
Offline
So the loop proposal looks pretty good. It's very reasonable and the syntax is pretty LOLy.
There's still something we need to address here and it's not in the loop semantics, but in the looper semantics. You have a "IM IN YR <variable> EATIN YR <local-var>" This works great, except what kind of variables can we use for-eaches on? Does for-each just iterate over every slot in a bukkit? Can I override this behavior for my specific class (e.g. a File)?
Anyway, I'm not sure this belongs in the Loop spec or as an addendum to the Bukkit spec, but it needs to be determined. I like for-each, thank you for coming up with some ideas and posting them! We can argue over semantics a bit, but the just of your proposal (combined with the loops2 proposal) should fly pretty well in 1.3.
Offline
How is this:
A Default Iterator would come pre packaged for most bukkits. In the bukkit specification one should have a mechanic to manipulate the keys stack (which is what gets iterated through).
ANY Variable can be used in foreach... it essentially checks if the variable is not valid or null. We could make this cleaner by putting in a iterator notation. This would be in bukkit's spec obviously.
I would of course want a perl like solution: X R <BUKKIT>, BTW Iterates bukkit and places the value in X.
I'll peruse through the current specs and what's out there, and put one up for ya tomorrow.
Offline
X R <BUKKIT> deep-copies the bukkit into the variable X.
I agree about the default iterator, which would simply return each slot in the bukkit normally, but the function could be overridden (i.e. by an array bukkit that would only return the array elements, not the additional slots like the array manipulation functions). This is more or less consistent with the BEHAVIOR of Javascript iterators although unlike JS you can actually CONTROL it.
Note that all variables are bukkits according to the proposal, so iterating over a NUMBAR (floating-point number) will return all of the built-in functions on NUMBAR objects.
We need to define an iterator protocol if we're going to do this, however. It's nice to say that you want to be able to do this but you have to be able to define HOW it happens in LOLCODE itself so objects can customize the behavior. Since we currently don't have generators (i.e. "yield" expressions, which would require continuations, which is sort of a challenge to implement) we'd need some sort of iterator object that knows its current state and can, on demand, generate the next item in sequence. (That said, the base BUKKIT implementation might implement these, so that ALL objects are iterator objects.) I've touched on this in another thread somewhere, don't recall where.
Offline
A default iterator cycles through the keys stack to figure out which values to return.
What are the benefits of having no primitive variable types btw? Wouldn't that cause a lot more overhead?
Even java has primitve types.
I'm currently looking through the perldocs on Tie which shows how perl handles iteration underneath.
Last edited by bloodycelt (2008-02-14 21:24:48)
Offline
Java may have primitive types, but you have to deal with something called auto-boxing. Auto-boxing was a fix in Java 1.5 to allow int to be automatically cast to Integer. What's the difference? "int" is primitive "Integer" is an Object. It's actually very handy to have "primitives" be objects. You can add a lot of nice helper methods to the objects, and they follow the same semantics as everything else in the language.
PERL, having a sort of hacky syntax doesn't really suffer as heavily as Java from this. I like perl, Hashes, Arrays and Maps are nice. I even bind some modules to them every now and then (By that I mean creating objects).
Anyway, the other point I wanted to make is that LOLCode implementers can treat primitives as primitives as long as they look like objects in the code, everything is fine. For examples of this see Scala or Groovy. Groovy is an especially good language for showing the power of having primitives be objects.
so this isn't valid groovy code, but should be somewhat close to what you can achieve in real live (i forget the ACTUAL "context" operator)
context(DayCalculater) {
startingTime = 6.days.ago.at(1.30); // BTW Returns a java.util.Date
}Offline
Python allows (and in fact encourages) "+".join([1, 2, 3]) -- this little snippet outputs the string "1+2+3". Also conceptually (Python doesn't do this but imagine it) (0.0023).exponent and (0.0023).mantissa would be useful methods on a float object. Python also defines operators like + in terms of magic methods on the numeric class types, so 1 + 2 is equivalent to 1.__add__(2), and I want to use this in LOLCODE for user-defined number types. (With this feature, you could implement complex numbers or matrices in LOLCODE with no need for underlying implementation support.)
By the way:
O HAI IM BaseIterator
I HAS A walrus ITZ NOOB
HOW DUZ I maek YR walrus?
BTW, ideally you'll pass in a weakref
MAH walrus R walrus
IF U SAY SO
HOW DUZ I getNext?
DO NOT WANT UnimplementedFunction
IF U SAY SO
KTHX
O HAI IM ArrayIterator IM LIEK BaseIterator
I HAS A position ITZ 0
HOW DUZ I getNext?
I HAS A value ITZ MAH SRS MAH position MKAY
MAH position R SUM OF MAH position AN 1
FOUND YR value
IF U SAY SO
KTHX
HOW DUZ BUKKIT IterateNumeric?
I HAS A iterator ITZ A ArrayIterator WIT YR ME, BTW iterator = new ArrayIterator(this)
FOUND YR iterator
KTHX
I HAS A train ITZ A BUKKIT
train'Z 0 R "A"
train'Z 1 R "B"
train'Z 2 R "C"
IM IN YR train IterateNumeric YR boxcar
VISIBLE boxcar
IM OUTTA YR trainNaturally, this outputs:
A
B
C
Note, by the way, that I'm using "IM IN YR <bukkit> <function> YR <indexvariable> [TIL <condition>]"; we can use EATIN as the default iterator. If the <bukkit> parameter is a variable that doesn't exist, it falls back to the 1.2 interpretation of the statement. (Note that TIL <condition> still makes sense with an iterator object; you may want to stop the loop at a condition other than the end of the data.)
Just my idea. (That's a simplistic example, too; I'd actually want to maintain a little bit of metadata in the object itself so I can handle negative and discontinuous numeric indexes.)
Offline
Why create a function like that... just make a iterator function in the BUKKIT class, and override it in the subclass.
It should be:
I HAS A train ITZ A STACK, BTW BUKKIT is like Java class Object you would use stack.
IM IN YR train
VISIBLE IT
KTHX
IM IN YR train EATIN YR cars
VISIBLE cars
KTHX
IM IN YR train'Z custonIterator
VISIBLE IT
KTHX
IM IN YR train'Z customIterator EATIN YR cars
VISIBLE cars
KTHX
Offline
I considered that, but storing the state in the bukkit itself means you can't use it more than once at a time. I couldn't implement something like:
foreach($array as $a) {
foreach($array as $b) {
if($a != $b) doSomething();
}
}That's just a simple example where you want to do something with every combination of elements in the array. To make that work, each foreach() has to have its own iteration state instead of depending on the array to store the iteration state internally.
I'm not opposed to "IM IN YR <expression> [EATIN YR <variable>]" instead of "IM IN YR <expression> <iterator> [YR <variable>]" but my syntax is SLIGHTLY shorter
I'd put it up to a vote.
Offline
Wait, so instead of using IM OUTTA YR <label> to end loops, we're using KTHX? So is KTHX a general block ender then?
Offline
No, we're not using KTHX to end loops (although it does beg the question, is KTHX a better "code-block-ender" for ALL code blocks?
Anyway, Here's my $0.02:
You can have the syntax:
IM IN YR train
VISIBLE IT
IM OUTT YR trainAnd still be using an iterator. All bukkits should have some default method that returns an iterator over all the slots. This loop is just syntactic sugar for calling that. To explicitly call any other iterator, you use the following syntax.
IM IN YR train'Z CustomIterator
VISIBLE IT
IM OUTTA YR train'Z CustomIteratorOffline
Using the explicit iterators makes the IM OUTTA YR syntax start getting REALLY verbose. I'm cool with preserving the syntax for backwards compatibility, but maybe we should use KTHX now.
I agree with having to name explicit iterators. My only difference is that my syntax is:
IM IN YR <bukkit-expression> [<slot> [YR <index>]]
instead of
IM IN YR <iterator-expression> [EATIN YR <index>]
We can call the default iterator "EATIN" and the two syntaxes are identical for it.
The argument for my iterator is less obvious when you're calling it CustomIterator, but what if it's
IM IN YR kitty NOMMIN YR mous
As you see, a clever choice of iterator name makes the LOL-text look exactly how we want. Of course, if <bukkit-expression> is a single identifier that doesn't correspond with an existing object, we can fall back to LOLCODE 1.2 loop semantics, which are useful in their own right.
Offline
+10 Genius points.
I like it. Not sure if I like EATIN or NOMNOMNOM as the default iterator "slot". Either way, I vote for that style. (And KTHX for closing the loop).
(P.S. How we gonna support backwards capabilities completely? Some might be really really tough).
Offline
Actually, here's a thought for backwards compatibility, modifying my proposal a bit:
IM IN YR <label> [<slot> YR <bukkit-expr> [(TIL|WILE) <condition>]]
If you don't use <slot> YR <expr>, it's an infinite loop, as in 1.2.
If you don't use a <condition>, the loop only terminates with GTFO or DO NOT WANT. (Note: When using an iterator, DO NOT WANT in the iterator function indicates that iteration should halt.)
If <bukkit-expr>'Z <slot> exists, use it with the iterator protocol. Otherwise evaluate as per 1.2.
One difference between the two methods is that the iterator has to be invoked before the first loop, but the legacy protocol doesn't. I don't think anyone's going to be CONFUSED by this behavior, but implementors need to be aware.
Offline
I too like the verb part being a slot, but I'd suggest one thing for while-style loops: make the (TIL|WILE) <condition> part allowed even without <slot> YR <bukkit>. It's not as good lolcat, (IM IN YR ceiling WILE BOTH SAEM cheezburger AN NOOB), but it's at least consistent.
Offline
Fair enough, let's preserve that.
Offline
Actually:
I think we should use CAN or HAI or something to force backwards compatibility.
IM IN YR <bukkit|label> [<VERB> [YR <return value>]]...
VERB is a function that is called every time the loop iterates. The namespace would be any bukkit function, WILE or TILL.
You can string them together and it will check each in order and exit on a null or false value.
If the object is not a bukkit (ie not a variable) the loop creates a loop type bukkit which for 1.3 will just act as a label, but possibly later on we can put in some functionality for some advanced loop control.
Return values of a function in the loop statement default to IT, (so IT can be overwritten multiple times) unless specified by YR.
If no VERB is specified, then the function calls the bukkit's default loop context function (which can be overridden).
This would usually be an iterator (EATIN), but in some cases (Integers/Yarns), it just checks if null and returns the boolean.
Last edited by bloodycelt (2008-03-12 20:50:11)
Offline
I don't see a compelling difference between your syntax and mine, except for the ordering of the variables.
Offline
I think the main difference is the label and the bukkit are conflated; this might be a good thing because you don't always have to think of a loop label and you could be in a variable. But it's a bad thing for named breaks, if we have them, and the syntax doesn't work in LOL.
BTW bloodycelt's syntax IM IN YR X'Z CHEEZBURGERS EATIN YR NEXTBURGER
Hmm...I see another problem with both syntaxes: the "YR" before the bukkit-expr is grammatically unnecessary.
Last edited by jediknil (2008-03-13 19:57:07)
Offline
Your syntax is essentially identical to an earlier variant I had considered. (See post #12 above.) I made the change mostly for the sake of making the semantics for iterators more parallel to the semantics of non-iterator loops. (Also, named breaks.)
Perhaps we should take this to a vote after the current voting topic is resolved.
Offline
feel free to set up another topic. I don't mind voting for more than one thing at a time.
Offline
http://forum.lolcode.com/viewpoll.php?pid=4010
Poll and breakdown of the options.
Offline
Okay, the vote has finally come to a close.
IM IN YR <label> [<slot> YR <bukkit-expr>] [(TIL|WILE) <condition>]
BUKKIT will implement "EATIN" that iterates over all slots.
The label is used for named breaks (GTFO <label>) and named loop ends (IM OUTTA YR <label>).
Iteration happens using the following scheme:
* If the <slot> YR <bukkit-expr> clause is not provided, no iteration takes place; the block loops until the condition fails.
* If <bukkit-expr>'Z <slot> exists, each iteration invokes the slot and stores the return value in IT until the iterator raises an expression or the condition fails. (The iterator object will most likely have a function to return its current value as well.)
* If I'Z <slot> exists, each iteration applies <slot> to <bukkit-expr> in-place until the condition fails.
* If neither function exists, it's an error.
Offline
For the sake of, well, actually working with iterators, the condition shouldn't automatically overwrite IT. Just as a note to implementors.
Also, although it's sort of obvious, it should be stated that if neither clause is provided, the loop is infinite (or until a GTFO <label>, GTFO [of the whole function], or FOUND YR <expr>).
As for "The label is used for...named loop ends." Is there such a thing as an unnamed loop end, like KTHX or something? Or is IM OUTTA YR the only way to end a loop?
Offline
KTHX is an acceptable end-of-loop statement now, yes; I thought we discussed that earlier in this thread.
Good point about making an explicit mention of infinite loops.
JoshSuereth and I were doing further discussion of this, and we've come up with an interesting idea: If the label IS a bukkit, it's used as the scope of the block, like a WITH statement.
Offline