I added some basic control structures to the tutorial. However I left out quite a bit! Here are some extras!
1. Non-local goto ============= In a felix function only jumps to labels in the function are allowed. However a procedure can jump to any label in scope not masked by a function boundary (that is, you cannot jump out of or through a function). A jump to a label not in the same procedure is called a non-local goto. For example: proc f(x:int) { proc g() { if x < 0 goto negative; } g(); println$ "Non-negative"; return; negative:> println$ "Negative"; } A non-local goto is a bit like throwing and catching an exception. Non local gotos are not safe. A useful technique is to capture a non-local goto in a procedure and pass it as an argument to handle errors: proc doer (x:int, error: 1 -> 0) { if x < 0 call error; println$ "Non-negative"; } proc f(x:int) { proc error () { goto error-handler; } doer (x, error); println$ "OK"; error-handler:> println$ "ERROR-Negative"; } This unwinds the procedure stack like an exception. This example is safe. However you can write unsafe code by storing a closure containing a non-local goto somewhere and calling it after the procedure containing the target has returned. You can also pass it into a function and call it, which will not work either. Although non-local gotos are dangerous they're essential because often a goto that seems to be local isn't. Inside some constructions, such as matches, the action bodies are wrapped in procedures, so a jump out of them whilst no explicitly in a user defined procedure, are in fact inside a compiler defined procedure. On the other hand non-local jumps can be localised by inlining. 2. break, continue, and redo ====================== Most loops support break, and continue like C, and for loops also support redo which restarts the loop like continue without incrementing the control variable. however unlike C, these three construction REQUIRE a named loop, and take the name of the loop. For example myloop: while x >0 do blah; break myloop; done Of course, this means if you have nested loops you can specify which one to break out of. Much better than C :) 3. Return from =========== A procedural return can specify which procedure to return from. This allows "fast exit" from any parent. For example: proc f() { proc g () { return from f; } } 4. yield ====== A function may yield a value instead of returning it. If it does so, the function is a generator and must be called a generator. A yielding generator must be formed into a closure and stored into a variable. Yielding remembers the point of yield so that a subsequent invocation restarts just after the yield, so that yield is like an inside out subroutine call. For example gen seq () { for var i in 0 upto 2 do yield i; done return -1; } var seqgen = seq; println$ seqgen(); println$ seqgen(); ... A yielding generator can be a finite or infinte loop. If it terminates, then the final value should be returned not yielded. In this case subsequent calls to the generator will return the final value repeatedly. 5. Iterators ======== More on request .. :-) Suffice it to say an iterator is a generator that returns all the values of a data structure as Some x, and then infinite stream of None. There's special syntax for using them: for v in D do ... done where D is the data structure. This works for lists, arrays, indeed any data structure with a suitable generator called "iterator". There's also an advanced form which pattern matches the fetched values. 6. Fibres (fthreads) and threads (pthreads). ================================= And schannels and pchannels. Which are used to implement pipelines and futures. Summary: Felix has some of the most advanced control structures of any programming language. There are two kinds: basic ones, and derived ones built on top of the basic ones. For example, there are no while loops or for loops. They're all built with conditional gotos. Of the "basic" ones there are two kinds. Ones defined by the compiler, such as "goto". And ones defined (at least partly) in the C++ RTL. All the threading and coroutine stuff is defined in the RTL with a single operation provided by the compiler. The primitive there is _svc argument; which is a "service request" also called a "software interrupt" or a "kernel call". -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ Rapidly troubleshoot problems before they affect your business. Most IT organizations don't have a clear picture of how application performance affects their revenue. With AppDynamics, you get 100% visibility into your Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language