So I am now trying to “clean house” on where Spry stands today. This sweep through the old articles is a first step, then I will update the language manual to be 100% in sync with the implementation.
Let’s go through the articles from the beginning!
Things wrong in article one:
funciis now called
method, indicating it is a message to a receiver on the left
ifas been changed to the more Smalltalkish
then:else:(but shorter than
ifTrue:ifFalse:and reads nice)
^just like in Smalltalk
In article two:
- Context is now called Map. It’s the same as a Smalltalk Dictionary, but “Map” is a more popular term these days, and shorter.
- Get words use
^(which is return). This actually looks kinda ok, it makes them resemble “variables” from other languages.
- The idea with a pluggable parser… I think I will skip that and replace with something else in pure Spry!
- The scoping prefixes
..have been removed and replaced with another way to assign.
- I wrote “This means Ni maintains no call stack of its own.” - no idea what I meant by that. Spry indeed has a stack of activation records.
In article three:
- There is no
ifelse, instead we have
- The argwords design mistake is still here, but… can be avoided by not using argwords nested, so use
[:x :y ^[x + y]]instead of
[^[:x + :y]]. So it will probably have to stay.
?is not used anymore, we can use
set?to check if an unevaluated word is bound, like
- Meaning of scopes are now (I have removed
x- look in locals and then all the way out.
@x- look in closest surrounding Map (self).
- Optional arguments have not been added, I don’t think I ever will add.
&has been changed to Smalltalk style
,for concatenation, but leaning towards
nilis slightly different:
nilis a value that means “no value”
undefhas been removed, it was a fun experiment
?-marks are used for funcs/methods that return booleans, convention.
!-mark is still unused.
selfis as the receiver for methods. It can be anything.
locals, returns the Map of the local scope.
activationreturns the current activation, not yet explored much but it’s there!
In article four:
- I later opted to call a Dictionary a Map, so it’s Map now :)
bindingsword is now
- The description of
objectis partly the way it works, yes, it takes a Map as argument and returns an “object”. But… this is done using tags that’s not described in this article.
- Also, the traits idea and thoughts around that is not what has been implemented later. The current Spry instead is exploring if methods can be defined for things with specific tags, and then if those methods can be automatically composed into “polymethods” so that two different modules can define methods with the same name - and they are “merged” into a polymethod that get’s bound to that name. When invoked the polymethod should “internally” pick which method to execute.
In article five:
- Yes, renamed to Spry. But… it’s sprylang.se, not .org
In article six:
- Yes, base idea of using compressed “Spry code” and store in a fast embedded database still stands! But I now have Rocksdb instead of Sophia, and a pure Nim implementation of Snappy instead of lz4 (it was too hard to get on various platforms)
- Yes, the current modules is implemented as described. Not tested much, but yes. I still think the base ideas stand.
- I did fix so that
Foo::barfirst finds Foo, and then looks in it. So it works for Maps in general, not just modules. And yes, you can then shadow a module with a global.
- To access “map members” I instead added
selfis now bound to the receiver of methods, this resolves members also. One issue though, if you use blocks (and not funcs) then nested blocks in a method sent as parameters to other methods will obviously not resolve to the lexical self, but to the receiving self. Changing the block to a func solves this.
- Lossless AST was something I did experiment with, but dropped it. A bit too crazy perhaps.
- So… otherwise it basically sounds like a good plan, but not used much (or implemented much) yet.
In article nine
- This article is mostly “fluff” but there is one important thing I need to improve - “Live within the prototype”. In other words, Spry code should be edited, browsed and debugged in Spry tools. I need to try to get that going!
In article ten
- Nothing to note, except that yeah, Nim is fast and Spry is slow :)
- Most of this article seems quite correct and according to plan.
And finally, in article twelve
- Most here seems fine too.
- I have added
:=for reassignment. If no existing binding is found there will be an error (not fixed yet). So
=will work fine for single assignment, and will assign in local scope. And
:=signify reassignment and will lookup outwards before assigning.
- I have removed
undef. It felt neat but get’s confusing. Maps can still hold nil, it’s a valid value - if you want to check for a missing binding you will have to use explicit calls to do it instead, just as in Smalltalk.
- I have removed
..scoping words. They can instead be implemented as direct access to
activation parent lookup:etc.
- I have implemented a base
try:catch:mechanism but more to come.
More on error handling in the next article!