Objective-S: architecture-oriented language based on Smalltalk and Objective-C
objective.st
objective.st
Also, the "Object Templates" block is misconfigured.
Obj-S (originally Objective-SmallTalk) is a Smalltalk on top of the Obj-C runtime.
why not? isn't that the property of any RPC interface? can't RPC be completely language agnostic? as far as i understand this all depends on how flexible the RPC interface is.
i have certainly seen RPC interfaces in high level languages that allow me to call any object or function in the target system. in fact, i am working with a platform written in pike that has such an interface. pike is a high level language like python or smalltalk, and the RPC interface of this platform has clients in java and php where i can access server side objects as if they were part of the client. like i could with CORBA or others.
there is no reason why smalltalk could not support something similar.
For example, assuming that multiple entrypoints can share a lazily-initialised singleton environment then how should concurrent calls into the environment be handled? What about asynchronous callbacks? And so on.
Or more generally: “How can Smalltalk be integrated into an existing - or new - non-Smalltalk system?” - and it seems to me the answer is “it’s complicated” and not as simple as invoking a thread-safe C-style export that’s automatically generated by the Smalltalk toolchain.
if i understand you correctly then you seem to suggest that embedding smalltalk into a c environment is not trivial because smalltalk has its own runtime.
that is something that i agree with. but here is my confusion: how is that different from CORBA? doesn't that also just allow connecting two distributed runtime systems?
so my understanding is that it would be possible to have a c<->smalltalk bridge just like CORBA, (and that's the same kind of bridge in the pike based platform i mentioned between java/php<->pike) but both are different from embedding smalltalk outright.
all that said, from what i understand objective-smalltalk is something different entirely, it is a smalltalk environment with an objective-c based runtime, more like clojure or other languages on top of java.
In fact, you can get C-level performance with Smalltalk levels of encapsulation and dynamicism if you pay just a little attention. See iOS and macOS Performance Tuning: Cocoa, Cocoa Touch, Objective-C, and Swift: https://www.amazon.com/gp/product/0321842847/ref=as_li_tl?ie...
2014: https://news.ycombinator.com/item?id=7161566
2019:
https://news.ycombinator.com/item?id=18964665
A small (and objective) taste of Objective-Smalltalk: https://news.ycombinator.com/item?id=19113476
Presenting (in) Objective-Smalltalk: https://news.ycombinator.com/item?id=21552264
2020: Embedding Objective-Smalltalk: https://news.ycombinator.com/item?id=23176942
In their 'About' page, they say: "The theoretical foundation for Objective-S is Mary Shaw's Procedure Calls Are the Assembly Language of Software Interconnection: Connectors Deserve First-Class Status."
https://resources.sei.cmu.edu/library/asset-view.cfm?assetid...
So I skimmed M. Shaw's (1994) paper [1] and it is very much a dated concern. The main thrust of her critique is valid only in the context of monolithical systems depending on a linker to assemble a composite system ("architecture"). She is basically arguing for language semantics capable of expressing connecting diverse libraries in an e.g. Unix Pipes fashion. For example, one of her criticisms of existing languages (and linkers) is namespace collisions. The other is asymmetry of connecting modules. And finally (and she's entirely right about this too) that the definition of the final [monolith] system's "structure" is dispersed in various "import" directives in constituent modules.
But again, this seems to be an entirely dated concern and a completely mute point in the current regiment of networked processes.
So, to this thread's raised eyebrows regarding "general purpose language" and the language website's (actually pedantically correct) notion of "domain specific languages for the domain of algorithms", hopefully above will make the matter more clear. The "[DSL] of algorithms" is what you write your e.g. "microservice". Arguably, these are, in fact, purely algorithmic constructs. And something along the lines of M. Shaw's ideas (but certainly not Objective-S as I skimmed it) would express the total system architecture.
[1]: it's just 12 pages so won't take too much time.
From my experience, what she said is still highly relevant.
Maybe I can share my own viewpoint first: Imagine you want to use a third party dependency from GitHub. The first thing you will do is read the readme, which contains an architectural overview (if the project is documented well). This overview is very similar to what she describes in the paper - it's mostly prose and a few (non-formal) diagrams. Often, it's very hard to understand how the code fits into the bigger picture of the system. Also, a lot of info is implicit or only contained in prose (for example, which function do I call first?).
Wouldn't it be great if all this were standardized/codified in some way, and not just part of the documentation?
I'll try being tactful instead. And you on your part can try and read between the lines. (I have no desire to offend and my concern is not you.)
https://www.isri.cmu.edu/people/core-faculty/shaw-mary.html
She appears to be a highly accomplished academic.
> Often, it's very hard to understand how the code fits into the bigger picture of the system.
Progressively and now quite frequently in the field, usage of 3rd party code is formulaic. Progressively, as demand for software has increased, an equally downward pressure is brought to bear on value placed on contemplation.
> Wouldn't it be great if all this were standardized/codified in some way, and not just part of the documentation?
Yes. This is a thoughtful approach and would reduce the burden for the thoughtful programmer.
What if having a reasonably well-defined (maybe even "good") architecture were not more work, but less work?
And the "code" would be the architecture documentation, because you can actually just write down your architecture.
> Objective-S is the first general purpose programming language
Those kind of statements annoy me to be honest. Is it really true? Or is it over-the-top marketing hype?
For me – and I'm sure I'm not the only person who feels this way – it creates a negative first impression.
What we currently call general purpose languages are actually domain specific languages for the domain of algorithms."
So they are actually making a very bold claim.
"Isn't English the first (or older) general purpose programming language?"
Actually, more like Akkadian (the dialect that the /Code of Hammurabi/ is written in) - it isn't the first, but is the best-preserved set of rules and instructions - while not a program (as the Law isn't exactly a monoid[1] of linear instructions that mutate state) it could be used the basis for one.
[1] I hope I'm using the term correctly...
Wikipedia even has an article for "General-purpose (programming) language". This term is already taken and in use in computer science for decades, and used more broadly than apparently the OP would like.
> A general-purpose language is a computer language that is broadly applicable across application domains, and lacks specialized features for a particular domain. This is in contrast to a domain-specific language (DSL), which is specialized to a particular application domain. The line is not always sharp, as a language may have specialized features for a particular domain but be applicable more broadly, or conversely may in principle be capable of broad application but in practice used primarily for a specific domain
-- https://en.wikipedia.org/wiki/General-purpose_language
If you're going to say it meaning something different by it you should probably say what you mean. It just sounds like a weird boast.
I would probably say "While the goalposts are always moving as to what might be considered a 'general purpose programming language,' Objective S is, to my mind, the furthest in that direction so far."
Wordier, but should rub fewer people the wrong way.
Objective-S is an architecture-oriented programming language based loosely on Smalltalk and Objective-C. It currently runs on macOS, iOS and Linux, the latter using GNUstep.
By allowing general architectures, Objective-S is the first general purpose programming language.
What we currently call general purpose languages are actually domain specific languages for the domain of algorithms.
As it stands, it looks exactly like a domain specific language for the domain of "algorithms that expect to be run on a system with Cocoa or some approximation thereof". But I'm probably missing something, in which case that something could use some explication in the introduction or on the "about" page.
so I skip past that and just try to see if I can glean what something actually does
And yes, I am also annoyed by hyperbolic claims and titles, for example I remember a paper claiming a "Language for Cloud Services" (not sure whether they specifically mentioned AWS). Turned out to be a minimalistic FP language with rudimentary concurrency support. Applicability to cloud services was an obvious extension left to the reader. Grmph.
> Is it really true?
Yes, I believe it is true. It has taken me many years to figure this out, and I realise that it is highly non-obvious to the point of being startling and yes, seemingly over-the-top. The "About" explains it a little bit further:
> By allowing general architectures, Objective-S is the first general purpose programming language.
> What we currently call general purpose languages are actually domain specific languages for the domain of algorithms.
Maybe this should also go on the home page?
Anyway, a super short and also still pithy and incomplete justification: All current mainstream programming languages are descendants of ALGOL. The ALGOrithmic Language.
And that's not just a naming thing. I talk about this in much more detail here: "Can Programmers Escape the Gentle Tyranny of Call/Return?" (https://2020.programming-conference.org/details/salon-2020-p...)
In short, we started using procedures to both compute results, which was what we used computers for in general when we started this CS thing, and then incidentally also to organise those programs. This worked out OK, because this organisational mechanism matched what we wanted our programs to do. It largely no longer does, but the idea that we must use procedural/functional abstraction to organise our programs is so deeply and unquestioningly entrenched as to justify the term "paradigmatic".
In fact, I would argue that the fact that we unironically refer to our "algorithm DSLs" as "general purpose programming languages" shows just how deeply entrenched the call/return architectural style is.
Anyway, this architectural mismatch ( http://repository.upenn.edu/cgi/viewcontent.cgi?article=1074... ) is now pervasive, Stéphane Chatty described it in detail for the domain of interactive programs: "Programs = Programs = Data + Algorithms + Architecture: consequences for interactive software engineering". (http://dl.ifip.org/db/conf/ehci/ehci2007/Chatty07.pdf)
So yes, to answer some of the sibling comments, you obviously can use these "algorithm DSLs" to solve more general, non-algorithmic, problems, but only because of Turing completeness. And even that is based on the notion of Algorithm:
"The Church–Turing thesis conjectures that any function whose values can be computed by an algorithm can be computed by a Turing machine,..." ( https://en.wikipedia.org/wiki/Turing_completeness )
In fact on the highly theoretical front, with which I am not particularly familiar with, arguments have been made that there are computation models beyond Turing machines (https://www.researchgate.net/publication/220459029_New_Model...):
Dynamic interaction of clients and servers on the Internet, an infinite adaptation from evolutionary computation, and robots sensing and acting are some examples of areas that cannot be properly described using Turing Machines and algorithms.
Anyway, coming back to day-to-day programming, the examples abound once you are aware of the potential for mismatch. (It's almost like confirmation bias in that way: once you know about it, you can see it everywhere...) For example:
I've run into plenty of situations where a streaming approach would be faster. The complexity of it always necessitates making a slower conventional version. (wait for all the data to load into memory and the operate on it) the conventional approach is easier to debug and get working. 90% of the time, the gains from streaming aren't worth the added effort.
https://news.ycombinator.com/item?id=22225991
Why is the "conventional approach" easier to debug and get working? Because it is supported in the language. That's why it is conventional in the first place. And so we keep doing things that are not quite right, and the code piles on.
More generally, as Alan Kay put it: code seems "large" and "complicated" for what it does. (https://www.youtube.com/watch?v=ubaX1Smg6pY&t=126s).
Or Eric Schmidt, who wanted to invite the Gmail team for a chat in a meeting room, only to find out that it was 150+ people:
One of the complaints I have is that the teams doing products that you see are far larger than they should be. And that's a failure of architecture
https://www.youtube.com/watch?v=hcRxFRgNpns&t=3591s
I am sure everyone who has programmed for a while has had this gut feeling: this is far too much drudgery and detail work for what we're doing. I've had this since University, but it really hit home when I was asked to help on Wunderlist architecture. It was an ungodly amount of code for the iOS/macOS clients, and we were doing a fracking To Do List! And as Eric said, it is a problem of architecture. And it is hard to get the architecture right when there is a mismatch between the architecture that the program needs and the architecture that your programming language proscribes!
Now that's obviously not the only problem. But it is a biggy.
I've read the paper and to be frank: I'm taken aback at how you brush away FRP in Chapter 9. And with an example in Java streams, of all languages/frameworks.
Having to implement Builder methods? No named components/difficult to encapsulate because lambdas??
No, what you show with that example is not the "gentle tyranny" of call/return, it's the "gentle tyranny" of Java (which OTOH I find a surprisingly fitting phrase :) ).
Thanks! And sorry, I guess, I am still figuring this out and so it's not as coherent as I would like.
>I'm taken aback at how you brush away FRP in Chapter 9
Sorry, page limit, I was simply out of space. I've done more thorough takedowns^H^H^H^H^H^H^H^H^H^H^Hanalyses of Rx elsewhere. (FRP is really something else, as Conal Eliot tirelessly keeps pointing out).
Mind you, bringing dataflow to mainstream programming is a Good Thing™, and in some ways Rx accomplishes that. But the hoops you have to jump through to get there are...oh boy.
> Java streams
Hmm...I found the issues in other frameworks to be very similar.
Enjoy!
> The last few weeks, I spent a little time getting Objective-S working well on the Raspberry Pi, specifically my Pi400. It's a really wonderful little machine, and the form factor and price remind me very much of the early personal computers.
The Apple II I bought in grad school in 1980 was roughly $10,000 in current dollars. I'm not sure how the price of a Raspberry Pi could remind him of this.
Judge his code, not his prose?
The Apple ][ doesn't even have the "computer in keyboard" form-factor.
And yes, the Raspi is unimaginably more capable. In fact, I still want to do a "how it started" vs. "how it's going" putting the Raspi next to my >$10K NeXT cube. The Cube with the 256MB, slow, huge, washing-mashine-noisy optical drive that can "hold your universe" (no it couldn't), vs. the Raspi's equally removable but silent and infinitely more portable microSD with 16GB (or more after-market).
And both computers come/came with a copy of Mathematica. And I also still have the box for my copy of ParcPlace (!) Smalltalk for the NeXT. Maybe I should make a tiny box for ObjS just to have the side-by-side?
The papers go into a bit more detail, http://objective.st/Publications/ but the academic publishing process is also slow.
Another difficulty is that it is really different, but (or therefore) in unexpected places. Coming from Smalltalk background, I would be looking primarily at what it does with messaging and objects, and there Objective-S is almost completely unremarkable. It has HOM built in, but that would be easy to add, it uses {} instead of [] for blocks and has some actual syntax for defining methods and classes. Whatever. ¯\_(ツ)_/¯
The interesting stuff starts with the polymorphic identifiers, the URIs. Which, coming from a Smalltalk background I would probably note as being slightly funky, but then move on to get to the interesting bits, because identifiers in Smalltalk aren't particularly relevant.
However, URIs are foundational to the REST architectural style, which turns the Smalltalk idea on its head: interfaces are state-oriented (GET, PUT, DELETE as verbs + complex identifiers), computation is hidden. In Smalltalk, interfaces are "computational" (message-based) and state is hidden. With ObjS, you can easily express systems in an in-process REST architectural style. See the "Storage Combinators" paper linked from the site and the "In Process REST at the BBC" book chapter (https://link.springer.com/chapter/10.1007%2F978-1-4614-9299-...)
There are also what I call "property paths", which can be used in store definitions. They're kind of like the URL routes you find in frameworks like Flask, Sinatra, Rails, but generalized and integrated into the language. In-Process REST :). These I haven't put on the site at all yet, partly because I haven't gotten around to it, partly because they're not published yet.
Here is a short example, which adapts some introspection functionality as a store/scheme/in-process REST "server".
scheme ClassBrowserAdapter {
/. {
|= {
MPWClassMirror allUsefulClasses collect name.
}
}
/:className/instanceMethods {
|= {
mirror := MPWClassMirror mirrorWithClassNamed:className.
mirror methodMirrors collect name.
}
}
/:className/classMethods {
|= {
mirror := MPWMetaClassMirror mirrorWithClassNamed:className.
mirror methodMirrors collect name.
}
}
}
This can then be served via HTTP, plugged into a generic GUI browser (which also browses filesystems) or combined with other storage combinators. Again, the paper gives a lot more detail.Another example is from some recent experimentation with a Raspi I just wrote about (https://news.ycombinator.com/item?id=27099738). With a simple store, I can use the following code to turn on a GPI pin (hooked up to an LED):
gpio:17 ← 1.
OK, sort of nice, but so what? Well, I can connect things up, so if I wanted to get the LED to blink, I would hook up the pin to a blinker object: blinker → ref:gpio:17
The → is a generic "connect these two things" operator, so maybe the generic "connector". In this case, it is connecting two dataflow components: the blinker is a source that repeatedly outputs alternating ones and zeros, and the ref: is a reference to the variable in question, rather than the value itself, and any variable can act as a sink, writing to it just sets the value.I could also connect the blinker to stdout:
blinker → stdout.
In which case it starts writing 01010101... to the console. I can also connect the blinker to a file: blinker → ref:file/tmp/alternating.txt
In this case, the file contents will oscillate between 0 and 1. And so on and so forth for dataflow-ish types of architectures. Of course, that also works for connecting up UIs. NoteSo that's three architectural styles that are supported naturally by having the required connectors at hand:
1. Standard call/return in the form of Smalltalk-style messaging, extended with HOM
2. (In-Process) REST with stores, storage-combinators and property paths, supported by polymorphic identifiers
3. Dataflow, also supported by PIs.
And it turns out that with PIs, dataflow and storage-combinators, you get dataflow constraints almost for free, so that would be (4). In addition, there are notification protocols, which adapt between messaging and implicit invocation (5).
I hope this helps.
I dug more here: http://objective.st/About
I think if I were to summarize what that page says, it is that objective S is attempting to be an omni-paradigm language. That’s what they mean when they claim “the first general purpose...”.
That still seems like over the top marketing hype.
[1] https://en.wikipedia.org/wiki/S_(programming_language)?wprov...
https://blog.metaobject.com/2019/12/the-4-stages-of-objectiv...
"While Swift fixes some of Objective-C's most obvious flaws that were due to it being constructed by crashing two existing languages into each other, it discards the good with the bad. With a vengeance. Objective-S also discards the bad, while enhancing the good and taking it to an entirely new level."
So Swift is Obj-C without the bad parts, but also without some good parts, but Obj-S is Obj-C without the bad parts and the good parts are gooder.
I'm sorry but that's a poor elevator pitch about... anything. Gotta get more specific.
Still very short: Swift improves on and really doubles down on the algorithmic parts. But that's not where the actual problems are [Stroustroup]:
“C with Classes was explicitly de- signed to allow better program organisation; computation was considered a problem solved by C”
Objective-C is also largely algorithmic, but flexible enough that you could create some decent architectural adapters. Building and using these architectural adapters is where the magic was. As an algorithmic languages it was at best mediocre. Swift not only doubles down on the algorithmics, and yes, it is better at those if you don't consider performance, but also tightens things up so creating those sorts of architectural adapters becomes harder if not impossible.
What Objective-S does is take a look at all those architectural adapters we're building using somewhat rickety metaprogramming and instead of forbidding that goes "hey, we seem to want and need to program with a combination of different architectural styles, let's make that possible using plain old programming, rather than fancy metaprogramming". And in order to make that possible with plain programming, the language has to naturally support different architectural styles.
And of course they really, really went in the wrong direction with the tooling.
The Unix stdio library, for example, is an architectural adapter between the pipes and filters architectural style of the shell and the call/return architectural style of C.
I can't tell you why Swift would "not be suitable" for it as I never claimed that it wasn't.
What I did claim is that it is less suitable for writing these kinds of adapters between its native architectural style and non-native architectural styles, because it is more restrictive. And being more restrictive is entirely intentional.
And being more restrictive is probably a Good Thing™, overall, in order to prevent silly mistakes, f it weren't for the fact that large parts of the programs we write require, well "strongly request", different architectural styles.
Now if you were actually able to express different architectural styles naturally within the language, you wouldn't need to do so many unsafe metaprogramm-y hackish things.
¯\_(ツ)_/¯
If you actually support different architectural styles in the language, like in Objective-S, then you don’t have to resort to the kinds of hackish implementations that were necessary, but at least possible and reasonably easy in Objective-C.
And that are still necessary, but much more difficult in Swift, because it (rightly) tries to restrict hackish things, but (wrongly) still doesn’t support other needed architectural styles.