Marcel Weiher has been stubbornly treading his own path for more than a decade. As the iOS/macOS world moves towards Swift, he goes back to Smalltalk principles. As Apple introduces SwiftUI to appease the webdev crowd raised on React, he builds his own small and efficient GUI story.
Just checked and it's still up, hasn't even restarted.
Not sure why you think the presence of copyright makes something open-source. All open-source licenses depend on copyright, otherwise the code would be in the public domain.
IANAL, but I thought the phrase "All Rights Reserved" was in direct opposition to "Some rights reserved, some rights released under the following conditions" upon which Open Source licenses are based
So, yes, AIUI all creative works ever have copyright, but only Open Source grants rights to others, such as folks who might want to contribute to your project
I agree with the Objective-S goals [1], and it is cool to see research in this direction.
Are the mechanisms for defining architectural styles and some predefined styles (OO call/return, pipes & filters, REST and event broadcast) all that is new from Objective-S? Any other future goals? These seem relatively easy to implement as e.g. Lisp macros? Clojure supports many of these.
Personally, I would like to see more research in program semantics. I think languages should try to reduce expressiveness whenever possible by offering mechanisms to do so, i.e. DSLs and DSL tools. Along with the total lack of popularity of design-by-contract / Hoare logic / refinement types, I think this is the biggest mistake in modern language design.
In other fields, engineers strive to use components and to combine them in ways that yield artifacts with provable properties. An elementary example of this are truss structures in mechanical engineering.
There is not that much research direction in this area. Personally, I like Dafny [2]. There is quite a lot of research on advanced type systems and theorem proving, but I think there is still a big gap in usability and automation. I think DSLs to restrict semantics + automated program analyses could be an excellent alternative. Infer [3] is pretty nice. Similar approaches that targeted a language with better semantics would be able to offer a lot more guarantees.
Marcel, it might help non-language design experts like me to wrap their head around Objective-S and the notion that "OO call/return, pipes & filters, REST and event broadcast" are just (higher-order?) styles that can be implemented in a truly general purpose language (i.e. Objective-S) by providing concrete examples of how Objective-S does this and other presumably-general-purpose-but-not-actually-according-to-you do not?
Is functional programming yet another style, or is it a subset of call/return, or a subset of pipes & filters? If it is its own style, how might Objective-S implement this style? What would map-reduce look like? What about higher order functions and currying?
Or is Objective-S itself at root a functional language? You've said very categorically in another comment that Objective-S is NOT just reinventing Lisp. Can you explain?
Perhaps my questions don't make any sense. As I said, I'm no meta-language expert.
It looks to me like the situation we have today is that architectural components are deployed as separate binaries ( queues, proxies, web server etc), with PL being used mostly as glue code passing data between them using client apis.
Provided i correctly understood Objective-S endgoal, what makes you think integrating them into a language runtime will lead to better results ?
While there is support for autocomplete in the Stsh framework (for the interactive shell, but you can use it independently), there is no LSP support yet.
May I ask what you would be interested in doing with it?
How much of this is tied to Apple frameworks? I noticed that the Linux support requires GNUStep, so I'm assuming quite a bit? The impression I'm getting is that this requires a non-trivial, Apple-flavored runtime to be useful. GNUStep apps are pretty awful experiences today due to being based on outdated Nextstep UI concepts that do no adapt well to anything other than MacOS.
Is this meant to be used for creating GUI apps? Because if it is, relying on the ancient GNUStep for multiplatform support seems suspect. And if it's primarily intended for Mac/iOS development, then why should someone use this over Objective-C/Swift?
(btw no hate for GNUStep here, I've played with it in the past and think it's awesome, just not very relevant nowadays)
It seems the amount of code you need to write to get overly-specific common things done is extremely small compared to Swift, Obj-C, Rust, Java, Go, or Python.
> It uses the host platform's C ABI. It dose not require a VM.
to me thats whats cool about obj-c, not the syntax or whatever, but the runtime
that you can construct classes and methods at runtime just like a "vm" but much simpler and lightweight... its amazing to me that apple never made a construct-the-app-while-its-running type of rapid development tool... the pieces were all there afaik
Alan Kay said:
"Current software is built like the pyramids... By the arduous labour of thousands of slaves.
That is because we still don't have the equivalent of the Arch. That allows Notre Dame to have 3 times the volume of the keeps pyramid with a third of the mass."
Since it seems you are building such an arch I thing a good name could be:
I've watched Marcel's efforts with admiration for his commitment for a long time.
I looked at this and browsed some of the examples, and something clicked for me finally. I did a good solid 20 years of dedicated Smalltalk. When I started doing Objective-C, I was glad I could send messages, but noticed a number of differences. One of the things that you don't see just comparing syntax between Smalltalk and Objective-C is some of the deeper differences. Objective-S, like Objective-C, has type annotations. In ObjectiveC, there is a preference for void return types. Smalltalk, has no annotations, but all functions methods return. If you don't specifically return something from a method, self is the implicit return type. For any closure, it's always the last value of the expressions. It made cascading messages really easy, because methods tended to return the thing you wanted most of the time. When I started doing Objective-C, I commented on this lack of object return. I don't recall what the answers were, but it was clear that ship had sailed. :)
Since then, as I've sailed with Swift and Kotlin and Python, it's clear that that is the dominant pattern. Python, which doesn't have types, still returns None when nothing is specified. And then last year, I did some work on Erlang/Elixir. Like Smalltalk, all functions return something. You can return nil if you want, but you have to make the effort to do so. Otherwise, you just get the result of the last expression. And I loved it. It makes it so you can compose functional chains really easy and idiomatic.
It's led me to wonder why any language that wants to be more "functional" has a Void return type. And once again impressed that Smalltalk, for all of its OOness, is really quite functional in some ways. Functional programming, is of course, many things. But one of them is obviously the good old f(x) -> y thing we learn in high school. Functions take input, and return output. A function that returns nothing, isn't that useful. But we also have computerese "functions" that are more "subroutines". An imperative sequence of steps designed to produce a certain side effect. When one makes a Void function, it seems one is essentially saying "not interested in functional here, just want side effects." I'm not as opposed to side effect programming as some, but I guess I prefer the approach like Smalltalk and Elixir which strongly encourages returns of some value (even if ignored) so that one can be simultaneously functional and side-affecty.
I'm disappointed that Objective-S didn't embrace the no-such-thing-as-a-void-return philosophy of Smalltalk, even while lifting so much from Smalltalk.
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:
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:
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?
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:
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 :-)
It's not obvious how Objective-S handles unreliable resources.
I ask because every remote resource is unreliable on several levels, and it's often both important and impossible to figure out which level is misbehaving. (Is AWS down, Comcast, my router? Or did I fat-finger some part of the URI?)
* the "Object templates" sample code ends outside the code box.
* Section "Messages": this whole sentence is basically a typo:
- expressions are handlde by message conneectors, and again like Smalltalk, Objective-S distinguishes three kinds of messaege...
- Objective-S has two mechanisms for chaining muliple messages
What text editor is the author using? Virtually every editor nowadays supports spellchecking.
I still remember my horror when I saw the pain of something as simple as string concatenation in Objective-C. The community literally has to write special micros to make joining a string palatable [1]. I salute the brave souls who made OSX/iOS apps before Swift.
Agreed. But once you get some macros (or categories) then Objective-C becomes a great language.
Is both elegant and very powerful as it is has the perfect balance between a static and a dynamic language.
Swift on the other had is a language where wonks decided to throw every silly feature they thought off to the point that is becoming more complex than even Scala.
I wished Swift was just a modernized Objective-C with a normal non bracket syntax and some extra facilities that it was missing.
> Swift on the other had is a language where wonks decided to throw every silly feature they thought off to the point that is becoming more complex than even Scala.
What features in particular do you think represent unjustified complexity?
Swift is not my favorite, but I wouldn’t consider it to be a “kitchen-sink” language, and it’s certainly less complicated than Scala.
`guard` has its time and place, which is to refactor pyramids of doom away. The number of nested `if let` statements I've seen, and written, is upsetting.
I don't think they quite address the same thing. `guard` isn't just an `if` statement that looks for the negative of a Boolean; it also forces handing control flow out of scope in a consistent way — you cannot write a `guard` statement without also deciding how you'll exit the scope if the Boolean is false.
The developer not being made to do so, and just embedding conditions within conditions, is how the pyramids of doom are constructed to begin with.
Your example is worse than stringWithFormat: for the same reason C++ iostreams are worse than format strings.
It's hard to control once you want anything more interesting than + and it's not localizable. Complaining that a function call's name is too long doesn't matter at all.
If you think that function name length doesn't matter you haven't written enough ObjC yet. It matters. Source code shouldn't read like Tolstoy.
ObjC itself is not responsible, it's NeXT and Apple's fault for perpetuating that abominable naming convention for much too long.
As for localisation, only a tiny fraction of strings in a software program are user visible. I don't think we should be designing language syntax around that edge case.
I'm sure I've written more than most other people currently alive.
ObjC is one of the most readable languages around. That's mostly because of the param:value syntax, which is much better than C-like syntax because you can see the parameter names. But the long method names aren't a problem once you have autocompletion. They also make it clearer what the best name for a method is - if you call something fmt() you start needing to make up equally clever short names for everything else, and it becomes less principled.
For algorithmic string building, I'm not sure how often you want + (aka appendString:), appendFormat: or componentsJoinedByString: are more flexible.
>if you call something fmt() you start needing to make up equally clever short names for everything else, and it becomes less principled.
Not necessary. There's a very sensible "huffmanization" principle created within Perl/Raku community which says that the need for a name/token to be overly descriptive is inversely proportional to frequency of its usage. So you can have short names and they still be human-parseable just because they are used often, and your brain used to register it. FWIW they will be easier human-parseable, because longer words take longer to read. With this approach one can has both fmt, and formatSomethingSomewhereSomeday
1. param:value is used, but convention is param:value not the gratuitous Engrish verbingParamProposition:value ObjC inherited from Smalltalk.
2. param: is optional if the variable holding value in the calling function is named "param" at compile time. This pushes you to name your params "param" everywhere that makes sense.
Jakt's popularity is limited, obviously, but it's a compile-to-C++ language, so you could use it many places.
Actually, I'm glad its a method with a long-ish name. Operator-overloaded string concatenation makes something that can ruin your performance look innocent.
Also, I've never heard of any serious iOS/macOS dev complaining about this.
I can’t speak for other ObjC devs back when the iPhone SDK was released; but I remember just being so grateful that I had any tooling to develop for iOS that I was more than happy to overlook any ObjC weirdness/clunkiness.
ObjC is very simple (often confused with archaic), but also wildly complex. Once you wrap your head around the ObjC way of doing things, everything makes sense, is very consistent, and you could develop very effectively.
While this syntax is indeed popular in several languages it's deeply weird, it's like how English uses apostrophe S to do two very different things at the end of words.
The Add operation has a whole bunch of properties and this not only isn't most of them, it's arguably not any of them, the main argument for + as a string concatenate operator is "Well, people seem to like it". Which, I guess I/O streams doesn't even have that going for it, but it's a pretty terrible rationale.
Look, just grow string interpolate and write f"{foo}{bar}" or whatever as much as you like don't abuse unrelated operators.
Whatever you feel about operator overloading, it's way better than the Objective-C version, even the version floated by the defenders. String interpolation is even better, sure, but the + alternative isn't that bad. As you noted, natural language does the same kind of overloading and we seem to cope with it just fine.
Unfortunately OP submitted the About page rather than the home page. From https://objective.st:
> Objective-S is possibly the first general purpose programming language. It makes creating well-architected and efficient programs not only straightforward, but easy, fun and fast.
> Yes, this sounds insane, programming languages we call "general purpose" number in at least the hundreds, starting with C, Java, Smalltalk, Ruby, Python etc.
> However, these are actually DSLs for the domain of algorithms, and this architectural mismatch, the fact that we have to use algorithm DSLs for tasks that are not primarily algorithmic in nature lies at the heart of much of the pain we have in software development today.
I like what I've seen of Objective-S; I completely support and appreciate the thought you've put into it, but I don't think that's a great claim to make.
Implicit is the claim that C, Lisp, Modula-2 are not general purpose languages, which is ridiculous. You may not want to deal with C's various problems, and it may take pages and pages of code to do in C what one line of Objective-S could do, but doesn't mean it can't be done.
I read the rest of the About page and didn't see anything supporting this claim. What makes Objective-S more general than other languages? If it's the four architecture "styles" listed, I'm pretty sure other languages can do the same:
* OO and Call/Return: Supported by every OO language.
* Pipes and Filters: Supported by every functional programming language.
* REST: Supported by many modern languages. (Go springs to mind as a typical example.)
* Implicit Invocation / Event Broadcast: Supported by many modern languages.
I believe the argument is that this language has special syntax for these various "architectures", instead of other languages where you express those ideas with the syntax of calling/returning functions.
> What makes Objective-S more general than other languages?
They describe that on the site. The notion is that most of our modern languages are more geared towards expressing algorithms and data structures, and not so great for expressing programs better suited to different architectural styles that don't necessarily follow a strict call/return type of semantics.
That's not entirely wrong. You can build a library/eDSL in a call/return language that will implement other architectures, but it will still look and behave like a call/return abstraction. Ostensibly Objective-S's goal is to make programs written in other architectural styles look like they are expressed natively in those styles, rather than an embedding of that style in a call/return architecture.
I'd like to see Objective-S implement Prolog or other logic programming to put that claim to the test. The other architectures they list aren't too far from call/return style, but logic programming certainly is.
Thank you for getting it and expressing it so clearly.
> You can build a library/eDSL in a call/return language that will implement other architectures, but it will still look and behave like a call/return abstraction
EXACTLY!
We can build, but we cannot express. So it will look like a weird/complicated call/return abstraction, because it isn't "native". So you get a tradeoff between architecture and simplicity, a tradeoff that shouldn't be there. (And all sorts of other 2nd order effects).
> Ostensibly Objective-S's goal is to make programs written in other architectural styles look like they are expressed natively in those styles, rather than an embedding of that style in a call/return architecture.
EXACTLY!
We need to be able to express those alternative styles natively and naturally, otherwise we are always going to be stuck in the tradeoff between architecture and simplicity, or as I call it The Gentle Tyranny of Call/Return.
> I'd like to see Objective-S implement Prolog
That's actually on the list, as a stretch goal. One of my (many) inspirations was this great 1988 article about adding support for backtracking to Smalltalk, without modifying the kernel: https://dl.acm.org/doi/10.1145/62083.62094 A tour-de-force. And yet...not really something you'd ever use. The other problem is that Prolog, in my understanding, is actually too "algorithmic" or "procedural" to expend too much effort on, at least when you consider its interface After all, the basic interaction with Prolog is to ask it a question and then it rummages around in its database of rules and facts and spits out an answer.
I am personally more interested in constraints, particularly (one way) dataflow constraints. Those I am now able to get out of the other architectural components, and without significant algorithmic intermediation.
You don't seem to know prolog well if you consider more "algorithmic" or "procedural" than, say, smalltalk. Sure, it's not 100% declarative, because even prolog is bound by such down-to-earth concerns as performance and termination. But there is no such thing as a "function call" in prolog.
I for one would like to see you put your claims to the test and implement a prolog in objective-S, indeed. Half of it is backtracking; the other half is unification as the main connector. Good luck.
> You don't seem to know prolog well if you consider more "algorithmic" or "procedural" than, say, smalltalk.
Actually: I do. Which is why I gave the precise reasons for what I wrote, which in turn your critique does not touch on at all.
So again: Prolog is very much a system that computes answers to questions. If you have a Prolog-based system that does not, please point it out to me and I will be happy to have a look.
"computes answers to questions" applies to any system with a REPL. That's really not a technical term at all.
If you want to be more precise, you could say prolog tries to satisfy the goal it's passed (via unification and resolution). That's not the same as the call/return paradigm. The only unifying concept (heh) for these two is, well, "computes something".
Anyway, for me, that confirms that your statements are not grounded in anything but vague terms you throw around, like "algorithmic". If you want to convince people that your flavor of smalltalk is actually, qualitatively _more expressive_ than all the hundreds of other languages, you're going to have to define a precise notion of expressiveness and show that only your system matches it. Since you've recognized that it's just about being more expressive, since you can write anything in any language; you probably also need to have cold numbers on how much more expressive objective-S is.
You picked a different tool for each of the different entry, while the author is arguing their programming language is general purpose, because it allow to do each entry you listed, in a single language.
Right. A different _tool_ because they described paradigms aren’t language paradigms- they’re patterns or frameworks expressed more easily but also more commonly in some languages than others because of completely unrelated historical accidents.
We have different languages because we do different things with them, and any Turing complete language can achieve any desired program. So what we’re left with is a misunderstanding about what is the “language”, “runtime”, and … “pattern?”
There is no useful definition of “general purpose language” except to disqualify languages that are not general purpose. That’s a fine distinction to make when describing how SQL will never replace JavaScript, Java, or C- but a useless distinction when describing the characteristics of your new language that is also Turing complete.
In particular item 4 “Implicit Invocation / Event Broadcast” is one of those things that hides an enormous amount of implementation complexity that arguably shouldn’t be made magical. Like async / await or go channels, the details make all the difference and there’s not a one size fits all approach that you can take without creating serious problems for other cases. It has to be an opinionated and therefore (sometimes/often) approach depending on what you’re attempting to accomplish.
Yes, exactly: these architectural styles should not be built into the language. And (mostly) aren't, in Objective-S. You should be able to build them yourself within the language and then they should have linguistic support that is as good / indistinguishable from built-in stuff.
Just like Smalltalk does with, say collections: most languages have/had built-in support for one type of collection (or maybe two), typically arrays of a homogenous type. If you wanted to build your own collection, you could, but were limited with functional call syntax fora accessing that collection.
With Smalltalk, collections yourself create are on an equal footing with collections that are in the base library. And that's an idea that has slowly percolated through the PL community and to practice.
But not with architectural styles. Our mainstream programming languages typically support exactly one architectural style: call/return. That's the only one that allows abstraction. If you want a different one, you can build it, but you cannot express it. And that's a huge problem, as any non-default architectural style gets a huge expressiveness penalty.
Previous languages that support alternative architectural styles usually have exactly the problem you've described: they offer exactly one implementation of that architectural style baked into the language, and that's it (Go channels are an example). And if you need something even slightly different, you're back in implementing + expressing with call/return, because that's the only style that allows abstraction. Sigh.
With Objective-S, the idea is that you get to implement whatever you want in terms of architectural styles (connectors, components) and then get to surface it with syntax appropriate for architectural connection. And the implementation will usually also be call/return based, because that's what we currently have. Although I am starting to see places where I can actually implement a connector in terms of other connectors directly without mediating via procedure calls.
(The one-way dataflow connector |= can be built from a storage combinator and a notification mechanism, and these can be pluggable. Very neat, particularly because building dataflow constraints naturally was one of my goals and this exceeds that goal).
Of course there's a bit of a chicken/egg problem, in two variations: first, I must provide some "built-in" components and connectors that go outside the default set, otherwise the whole thing is useless. And there it turned out that the initial set (polymorphic write streams, storage combinators, dataflow constraints) turned out so useful and general that they sort of become "the thing", even though they aren't. The second, related chicken/egg problem is that both conceptually and from an implementation POV, we have to start somewhere concrete, because this is an abstraction mechanism that doesn't exist yet and thus nobody really has a clue how it should work. So things aren't as abstract/general yet as they should be.
Alright then, what if the architectural style one wants is type-level metaprogramming? Or even just having a rich type system with inference, like Haskell? Can objective-S do that? What about monads, typeclasses, etc. which are arguably pretty extensible and DSL-y too (see Xmonad for example)?
If not, maybe this whole definition of "general purpose" is just meaningless.
Hmm...not sure what you find gobbledygooky or jargon-y about this...it is about as clear as I can make it. I mean it is definitely a surprising even somewhat baffling insight, but once it is there it seems pretty clear.
1. Historically, computers were created to compute results (hence the name) using algorithms. So you have a function/procedure that you give parameters, it executes the algorithm, spits out the answer and terminates.
2. Programming languages reflect this. Heck, the granddaddy of most mainstream programming languages is ALGOL, the ALGOrithmic Language. https://en.wikipedia.org/wiki/ALGOL
3. The majority of programs/system today are not like (1). See for example Chatty:
"Another weakness of procedural and functional programming is that their viewpoint assumes a process by which "inputs" are transformed into "outputs"; [...] Ongoing behavior, not completion, is now of primary interest."
Happy to answer any more specific questions. Again, the insight is definitely somewhere between surprising and outright baffling, particularly because call/return is very much paradigmatic in the Kuhnian sense: a set of shared and implicit assumptions, so things we don't even think about but that form the basis of everything else.
Historically programming languages were designed to transform some initial state of the machine to some other state having some specified desirable properties. An algorithm is simply an “effective procedure” for instructing the state machine on how to go about modifying itself to achieve that end. Computing functions can and has been a use case sure, but it’s never been the only one. Simulation for example has a long history in computing. In the simulation use case there is no defined end, you just let it run and observe.
Of course one can model each state transition as a function from machine state to machine state, but that’s just a mathematical way of talking about the machine and not a programming paradigm.
You can see the legacy of the above in C, where many problems are best expressed directly as state machines. There is some confusion here because C chose to conflate functions, procedures, and subroutines, so code organization encourages use of C functions. The void return type is a workaround. It would also be idiomatic C to, for example, dispense with functions and use labels and switch/goto to organize state transitions.
Your confusion is understandable since virtually every programming language in widespread use today is at least in some sense a spiritual successor to C in the sense of adopting many of its conventions.
By the way I think Objective-S is interesting and I am glad it’s being developed. So please consider impressing readers with what actually is impressive about it.
And then there's some Lisp descendants, though those can't really be considered mainstream. Lisp's core is eval/apply.
Prolog is an interesting case, but in many ways it just embeds the algorithm in the language. From an outside perspective, you give it something to evaluate and it runs off and returns an answer.
The main outlier is the Unix shell, which, like Objective-S, is connect + run: you configure a pipeline out of filters, connect them up and then run the whole thing. And this can and will continue running indefinitely. Call/return is sort of a (common) special case. And that's interesting, because it seems to actually be easier to make call/return a special case of connect+run, but we do it the other way around.
It doesn’t appear that you understood anything I said.
This might be because you observably don’t know what an algorithm is. It has nothing at all intrinsically to do with call and return.
I’m afraid any further discussion will be fruitless, but on the off chance you tire of getting predictable responses to ridiculous assertions that promote what you believe to be a deep insight, then please refer back and search for the insight required to understand what you’re being told here.
"Sub-routines seem to have two distinct uses in programmes. The first and most obvious use is for the evaluation of functions, a simple example being the evaluation of sine x given x. The second use is for the organization of processes..."
I didn’t respond regarding Algol because you said nothing of immediate relevance requiring a response. I’m familiar with the history of Algol 60. I’m not interested in regurgitating wikipedia with you. Here[1] is a good primary source on the history of programming and significance of Algol in context for you to read. Note that call/return is nowhere mentioned.
Stop chasing tangents and address your core misunderstanding. Algorithms are not call and return.
OK, thanks for clarifying that you did not understand what I wrote in the least bit and have no intention of learning, not even so far as looking at the relevant information on Wikipedia, which would help clear up your misunderstandings.
Once again: ALGOL is the ALGOrithmic Language. It might have something to do with algorithms. Now please tell me what the main structuring mechanism for code is in Algol (and C, for that matter).
Do you at least understand that any language derived from C is therefore also derived from ALGOL?
And nobody claimed that Algorithms "are" call/return. They are just intricately related in both history and current practice, particularly once we stopped treating "primitive" operations separately and instead started understanding them as functions/procedures as well. (In C, something like multiplication is considered an operation (via the * operator), whereas most current languages treat multiplication is considered a function that the compiler understands and will directly emit machine code for).
So please stop chasing tangents that have nothing to do with what I wrote and what I've done and address your core misunderstanding(s).
Let's put your claim that Objective-S can be used to implement different architectural styles to the test: implement Prolog or some other logic programming language as an architecture!
I think the other architectures you've listed there aren't different enough from the typical call/return style of algorithm-centered languages, but logic programming certainly is.
"The Data stack holds parameters for and results of subroutine calls. This distinction between control and data minimizes the cost of subroutine calls.
"The benefit of having a stack reserved for return addresses was that the other stack could be used freely for parameter passing, without having to be “balanced” before and after calls"
If you can build Objective-S in a language then isn't the language that contains the set of Objective-S and other languages in theory more general purpose? I'm not sure I get the definition.
Yes and? EVAL isn’t call/return, it’s a mathematical function from type S-expression to type S-expression modulo some details. At least it was to start, Lisp now has side effects which considerably opens up the domain of easily expressed programs.
Perhaps you’re confused because you’ve never done anything nontrivial in a modern Lisp and the word function is so heavily overloaded?
Here[1] is an example of the Actor model expressed in Common Lisp. It shows a paradigm that is very much not call and return expressed cleanly and directly.
> EVAL isn't call/return, it's a mathematical function
Hmm...a "function" you say. What do you do with a function in a computer system? I mean, for it to actually do something?
Look at it?
Digest it?
Sing it?
Or maybe...call it?
And when that function is done, after you called it what does it do?
Dissolve?
Perambulate?
Or maybe: return?
Of course, a function that you call and that then returns has absolutely nothing to do with the call/return architectural style. Sorry, my bad, what was I thinking?
And no, your example does not invalidate what I wrote, as it doesn't implement it "cleanly and directly", at least not to my standards. Maybe to yours, but not to mine. The problem with Lisp DSLs is that the result always just look like Lisp, and Lisp is eval/apply.
So
(send my-actor message_args)
very much looks like a Lisp function call. It seems to be the function "send" with arguments "my-actor" and "message_args". (Of course the Actor model is close enough that it might not matter). Which is exactly the problem we have in other languages.
At the very least, it would have to be
my-actor async messge_args
For it to qualify as resembling an actual send and not just another function call.
I can also write:
source.connect( target );
And to you that would apparently mean that I have implemented pipes and filters "cleanly and directly" in, say, C++ and Java. And it would be just as wrong.
If you think that the operator in a Lisp form needs to be a function and if it were a function that it needs to return, then that's not the case in Lisp for probably 50+ years.
Lisp is not generally following an eval/apply model and/or call/return model.
(send foo :beep)
This can mean:
* SEND is a function, it's is called with the evaluated args, it may return or not
* SEND is not a function and does something arbitrary
Generally the model is:
(operator ...)
a) Where operator can be a special operator, something built-in, which is not a function.
For example (throw 'foo "hello"), where THROW is a built-in special operator which transfers control.
b) it could be a function, which is more like a procedure. The function could also do transfer control to some other place and never return, for example by calling THROW or by other operators which transfer control
c) it could be a macro. The args don't need to be evaluated. Thus no eval/apply. The macro returns code, which gets executed. Again this could use other primitives, which transfer control.
d) it could be a function itself like ((lambda (x y) ...) 13 14)
What it needs: the first element in a Lisp form needs to be an operator, which is usually a symbol with some meaning: special operator, function, macro.
Scheme then in the mid 70s added that the first element is evaluated and can be a general variable. Thus in Common Lisp:
(let ((actor (create-actor :name 'foo)))
(send-async actor :init))
could be written in Scheme
(let ((actor (create-actor 'foo)))
(actor :init))
given that the actor would be a function object.
> my-actor async messge_args
Writing it as
(send my-actor :async message-args)
Is basically just a syntactic transformation. The semantics could be the same.
If we want write
(my-actor async message-args)
then one would typically
a) switch to a model like in Scheme, where the actor would be a function object
or
b) write a translator for a new language to ordinary Lisp
Objective-C has objective because C itself is not objected oriented. Objective-Smalltalk would be redundant. How about StepTalk or SmallStep? to honor the NextStep heritage, you know.
We already have LISP. Every once in a while someone invents a new language to solve some old problem, and as the new language evolves, it becomes closer and closer to LISP.
That's one thing I am acutely aware of and monitoring closely, and in fact it's one of the blog posts that's ripening to be released sometime: Am I building a Lisp?.
And every once in a while it looks like it might be that I am, in fact, arriving at a Lisp, but in the end they turn out to be false alarms, so the answer is still fairly resoundingly: No.
The only thing lisp seems to have not figured out yet is this small thing we call "Syntax", which the PL community mostly figured out 50 years ago : you write terse notations and the compiler builds up the tree for you, you don't layout the syntax tree yourself.
Lisp also seems to have a shortage of knowledgeable advocates who understands other programming languages enough to know that not everything is or needs to be a lisp.
I'm quite convinced he's onto something.