It's really interesting, because looking at very simple things make you think in depth about some issues that you may not really consider in Java proper. For example, this is the definition of a very simple structure:
package fr.moresmau.jp.floj.samples;
public class Simple(String data,int port){
}
So you can see that the package system is Java's and class definition are very similar. There are no constructor, so. Since null are not allowed (nulls are a huge source of bugs, I'll provide a Maybe object or something like that later),
the structure must have all its data filled in. If you want different operations to be done, you just create static functions that take parameters and create what you need, no need for several constructors. So the list of fields is entered straight after the name of the class.
Simple is a structure with a string and an int. It's easy enough to generate the constructor in Java:
package fr.moresmau.jp.floj.samples;
public class Simple{
public final String data;
public final int port;
public Simple(final String _data, final int _port){
if(_data==null){throw new NullPointerException("_data");}
this.data=_data;
this.port=_port;
}
...
The fields are immutable of course, so we don't bother with a getXXX() method, we just expose the field.
And you can then add setters that return a new object :
... public Simple setData(final String _data){
if(_data==null){throw new NullPointerException("_data");}
if (_data.equals(data)){return this;}
return new fr.moresmau.jp.floj.samples.Simple(_data,port);
}
public Simple setPort(final int _port){
if (_port==port){return this;}
return new fr.moresmau.jp.floj.samples.Simple(data,_port);
}
...
Note the null handling is not ideal, left for later. Note also we avoid superfluous creations if the data will not change.
So far, so good.
Then I decided to implement equals, so that equals is based on the data and not pointer equality:
...
public boolean equals(final java.lang.Object o){
if (this==o){return true;}
if (o instanceof fr.moresmau.jp.floj.samples.Simple){
fr.moresmau.jp.floj.samples.Simple co=(fr.moresmau.jp.floj.samples.Simple)o;
if (!this.data.equals(co.data)){return false;}
if (this.port!=co.port){return false;}
return true;
}
return false;
}
...
And with this of course the problem of overloaded equals method raises its head. If I want to allow subclasses to add more fields, my equals method won't work for subclasses.
If I check the exact class name in equals, subclasses that only add/overload methods will not be equals to superclasses.
So what can I do? I haven't decided. I could forbid subclasses to define more data fields (that's I think what you have in Haskell: you inherit functions from your type classes but no data).
I could also make the equals method final and not generate it for subclasses, but equality would then ignore the additional fields.
Another option would be to check the class name in that equals method and generate the proper equals method for all subclasses, but that may cause problems if we then extends the FLOJ class by a Java Class (which will be possible since we generate Java code).
But maybe it should be so, that a class is never equals to its subclasses? Returning equals between two instances that have the same data but different behavior (one instance has an overloaded method) is probably an error in the OO world...
Anyway, creating your own language is fun, I'm learning a lot and maybe I'll even end up with something usable!! I'll keep you posted on my progress.