Hi Travis,

thanks for the kind words!

Objective-S tries to be expression-oriented in its call/return parts, it even goes a bit further than Smalltalk in that the return of a method is the last expression of the method (like Erlang/Elixier, if I understood you correctly, and like Smalltalk blocks). For example here are some methods:

-<int>numberOfSteps { 8. }
-description { "<Task: title: {this:title} done: {this:done}>". }

and some property paths:

/:table/:index {
|= { self dictionariesForQuery: "select * from {table}" | at: index. }
}

/:table {
|= { self dictionariesForQuery: "select * from {table}". }
}

/:table/:column/:index {
|= { self dictionariesForQuery: "select * from {table}" | at: index. }
}

/:table/where/:column/:value {
|= { self dictionariesForQuery: "select * from {table} where {column} = {value}". }
}

In fact, I don't even have a return statement. I am not sure I can keep that up, but so far it appears to be working out OK. I've appropriated the "^" to mean "send result to next filter" in the pipes/filter style:

#!env stsh
filter toupper |{ ^object stringValue uppercaseString. }
(stdin -> toupper -> rawstdout ) run

This could probably be generalised so that it means "send result", which in a method means "to sender" and in a filter means "to next filter".

Coming back to void: if I want to have interop with Objective-C, I must also support void returns, and they do come in handy here and there. For example, stsh uses a method declaration in comments after the shebang to make scripts more method-like, including argument parsing and return values. The following script expects a single integer argument and prints the result of adding three to that number to stdout:

#!env st
#-addToThree:<int>arg
arg+3.

You will note that there is no printing code. The reason is that the "method declaration" says there will be a return value. That means stsh will take the value of the last expression of the script and print that. Very convenient (and "functional"/"expression-oriented"). It will also automatically parse the first command line arg to a number and assign to "arg". And if you don't give it an argument?

]./add3.stsh
<script> 1 missing parameters (of 1): arg = <missing>

However, sometimes you don't want the script to be expression-oriented, you want the script to be in charge of printing to stdout. The following script, for example, is stream-oriented, it does not have a return value per-se, but rather streams its results:

#!env st
#-<void>sawk:<ref>file
file csv: { :time :latitude :longitude :depth :magnitude |
stdout println:"Magnitude: {magnitude} location: {latitude},{longitude} time: {time}".
}.

(You can give the script the URL of the US Geological Service's earthquake endpoint and it will print out the earthquakes nicely formatted):

] ./earthquakes-sawk.st https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv
Magnitude: 2.8 location: 58.3441,-133.2808 time: 2022-08-19T10:19:16.173Z
Magnitude: 0.35 location: 33.5856667,-116.8071667 time: 2022-08-19T10:18:54.980Z
...

In this streaming cases, having a return and being expression-oriented/functional does not make sense, and of course Objective-S tries to generalize beyond call/return.

Objective-C's default return type actually is "id" [1], and methods tended to return either some result or self up to NeXTstep 3.3, just like Smalltalk. So what changed? Distributed Objects. If your receiver is a distributed object, having a return value means that you have to marshal something, send it over the wire and synchronise on the return value. So they removed the default self returns.

With regards to types: I like type annotations, as long as I am not forced to add them everywhere and not constrained to the expressiveness of the type system. Having a bit of (checked) documentation is super-helpful when browsing code, having to chase down senders and implementors in order to figure out what a method does is super annoying. And of course Objective-C (and C) interop is crucial, as is the ability to compile some code to be as efficient as equivalent C code without needing a Heldencompiler/HeldenJIT. As soon as I add native compilation :-)

[1] https://blog.metaobject.com/2014/03/cargo-cult-typing-or-obj...