Monthly Archives: April 2016

Method cascading

I finally have a tool from fluent interfaces toolbox I needed. Usually you have some type of container with a method:

def !add(elem T) Void
  %% adding element
end

Wait, or should be it like this:

def !add(elem T) 'Self
  %% adding element
  return this;
end

The second form allows method chaining, but on the other hand there is overhead of result passing no matter if anyone uses it or not. And what about returning boolean flag indicating whether adding was successful or not. In such case we couldn’t return the container.

Method cascading answers some of those questions, we don’t need a version which cooperates with us because we isolate the object and reuse it:

coll |> !add(a) |> !add(b);

b is not added to the outcome of adding a (it would be a method chaining), but to the isolated object on the left — coll. Of course sometimes method cascading can have the same effect as method chaining, but in general they are two distinct tools.

The above code is equivalent to:

coll!add(a);
coll!add(b);

You can find more about method cascading at Wikipedia.

I took the symbols of the pipe operator — but not the meaning — from Elm (if I remember correctly I first saw it in Seven More Languages in Seven Weeks by Bruce Tate et al) and initially I thought it was function cascading operator which is not.

Advertisement
Tagged ,

X-FullMoon: the first successful conversion

Time flies… in 2002 I wrote small, quick&dirty reminder script in Perl. Later I translated it to Ruby and now I translated it again to Skila. And it works!

Currently it is painfully slow, so I stick with Ruby version, but nevertheless I am happy because not only something compiled with Skila is working but it is also useful (after all, I am using this program for 14 years). The conversion was fruitful, I improved compiler a lot and I have ideas how to improve it further.

If you are curious the script is available online, and if you are curious even more here is the format of the data file (fullmoon.dates):

# comment
year-month-day;cycle;task_description;advance;day_of_week
year-month-day;cycle;executable_filename;! # note the semicolon

Year, month, cycle (in days), advance (in days), day of the week (the first one is Monday with value 1) are optional, so the minimal form is:

day;;task_description
day;;executable_filename;! 

Here is my reminder that on New Year’s Eve I should by some ice-cream:

12-31;;buy ice-cream;7

So every year (it is not set) on December 31 with advance of 7 days I will get this reminder. Here is the reminder that I should replace my documents:

2021-05-22;;update documents;10

This time exact date is given. And the last example:

2014-05-25;7;MOOC download

Starting from given day every week (7 days) I am reminded to download all the stuff from MOOC I am enrolled to.

Tagged

Blocks as expressions

The irony is the moment I finished this feature I realized it is not enough — I need also a tracking system which would allow to postpone initialization.

But at least when you need to do some precomputation and then initialize variables you can use entire block as initialization value:

let (yyyy,mm,dd)
  = * do
        let parts = s.split("-");
        // the outcome of the entire do-end block
        parts ++ "".copy((3-parts.count()));
      end

It is better than nothing but I would prefer to write:

let yyyy,mm,dd Int; // postponed initialization
do
  let parts = s.split("-");
  // initialization
  (yyyy,mm,dd) = *(parts ++ "".copy((3-parts.count())));
end

In both cases temporary variable parts does not leak, but I am more used to the latter form. On the other hand only the former will work with loops, unlike in Scala which returns just unit (void in Skila) I am going to add some muscles to them.

Tagged , ,

Rich loops just got richer

The only missing piece in rich loops was building continuation nested loops — here the old C-like loops were obviously winning. In order to move closer to the podium I made few improvements, the first one — I cannot decide if this is an ugly hack or well designed concept.

I introduced iterator providers. Iterator provider is an object which can provide an iterator (yes, a groundbreaking approach). Usually you can think of a sequence as an iterator provider but there is another one obvious candidate — an iterator itself. It just returns copy of this. Such addition allows loops to work with iterators directly:

let iter = some_coll.getIterator();
for elem in iter do
  •••  
end

The second improvement is allowing to iterate over non existing data — in rigid mathematical sense an empty set is a not equal to no set, however so far I don’t see any danger with treating them here the same:

let none ?[Int] = null;
for elem in none do
  •••  
end

The third improvement is the smallest, it just supports method chaining. Advancing iterator instead of returning true/false returns an optional iterator. On a successful iteration — the iterator itself, on a failure — null. This part will be changed as soon as I implement reference passing as it was done in Smalltalk.

Those three changes combined let you write nested loops without any effort:

let coll = [1,2,3];
top: for x in coll do
  for y in top.iterator do
    System.Terminal.stdOut.writeLine(x,",",y);  
  end
end

It will write such pairs — (1,1), (1,2), (1,3), (2,2), (2,3), (3,3). Please note there are pairs where y is equal to x. When this is undesired start nested loop from the next element in collection — i.e. advance the iterator.

let coll = [1,2,3];
top: for x in coll do
  for y in top.iterator!next() do
    System.Terminal.stdOut.writeLine(x,",",y);  
  end
end

You should see — (1,2), (1,3), (2,3).

The iterator attribute of the top control is a copy of an iterator used internally by compiler, so you can alter it any way you want, it won’t harm the outer or inner loop.

Except for optimizing the internal wiring of rich loops I am done here, the plan is 100% completed.

Tagged

In a shadow of the globals

While working on void and later true and false I realized I would like to make those names reserved, despite the fact they are not keywords. It seemed odd — I made an arbitrary decision because void was so ubiquitous. Or because it was placed in global namespace? It was so lame, definition of void looked like any other object, and yet out of the blue it was selected by me that it should be reserved name. What if another object happens to be that important, should I also hard code its name into compiler to make it reserved as well?

Or was it global namespace indeed? And that was all it mattered?

There are plenty of languages which allow you to put a function, a variable into a global namespace with typical advice that you should keep global entities to minimum. Skila was one of those languages.

But not any longer, add as many variables to global namespace as you like.

Yes, sure, go ahead.

Just keep in mind shadowing of namespaces in Skila is disabled. It is a trick which solves my dilemmas about making arbitrary decision with names, and it also enforces the discipline of polluting the namespaces, no more talking, just rules. Take a look how it works:

namespace DirtyPlayground
  let x Int = 5; 
  
  def func(x Int) // error
    •••  
  end
end

The first x effectively makes a reservation for its name for entire namespace (and its descendants), thus you cannot shadow it by declaring any local variable.

Tagged ,

Breaking news: void exists

While reading Expert F# 4.0, 4th ed. by Don Syme, Adam Granicz, Antonio Cisternino I realized it is about time to get rid of void no-value, well, something.

It simply does not fit in any way, no matter what magic I would use — like creating object for ?Void type, despite the fact it could have value as optional type, but it would mean no-value as Void type.

Thus Void is regular type as any other, void is a single possible value of it. Even if it hurts performance (the least of my problems) it makes language more consistent.

Tagged

Expressions everywhere plus optional parallel assignments

The more I work on Skila the more I appreciate features with uniform behaviour. Lately I tried to add basic tail call optimization for current function — nothing more is required than reassigning the arguments and jumping to the top of the function.

But since I use PHP as backend which has very strict distinction between expressions and statements I failed — function call is an expression and jump (goto) is a statement. This was enough to motivate me to rewrite language part of Skila to make all statements, control structures expressions. They don’t produce any values yet, it will take more effort than just changing grammar.

The second solid change is support for optional parallel assignments (and declarations). You could of course write such code by hand:

if year ?= (y_str to ?Int) 
   and month ?= (m_str to ?Int) then
  •••
end

But consider what will happen when month conversion fails — year part will be altered. Maybe it is intended, maybe not — for the latter case Skila provides transaction-like assignment:

if (year,month) ?= (y_str to ?Int , m_str to ?Int) then
  •••
end

The variables will be updated only if both conversions succeed.

Tagged , , ,