Zygomys – An embedded scripting language for Go
github.com
github.com
It's not not predominantly a functional programming language and has no rich set of immutable, persistent data structures.
So, it's no Clojure. But it is young. It may become a clojure but it seems presumptuous at this stage..
Why do you say that?
> no powerful macro system
It has macros that...look pretty powerful to me? What's your issue with them?
> doesn't share with Lisp the code-as-data philosophy
Can you flesh out your objections a bit more?
Edit: For the sake of anyone reading this later, the comment I was replying to originally said Zygomys wasn't a lisp, which seemed a bit odd. It has since been edited to say Zygomys isn't Clojure, which is quite correct.
zygo> x := 3; y := 5; if x + y == 8 { (println "we add up") } else { (println "wat?" ) }
still something being lisp is not really sufficient to claim it is clojure. clojure is much more.Perhaps a better analogy would be Groovy, rather than Clojure? (Of course, Groovy isn't "cool" these days, so I guess there's not much marketing juice in comparing your new language to it...)
I think of Apache Groovy as being to the JVM what bash is to Linux. You could compare it to bash.
There was even a Groovy on Rails framework, just to make the longing more obvious. From memory, Groovy only reinvented itself as a scripting language some years later.
Clojure is one of the most revolutionary programming languages of the last decade, I can't see how this mini-toy-language packaged as a Go library can be compared to the mighty Clojure with a straight face.
To my mind though, Clojure brought clarity to the JVM on issues of concurrency, state, mutability, object orientation and persistence and for that I will always love it.
https://www.reddit.com/r/Clojure/comments/3tha86/transducers...
Likewise Spec ideas are not new to old timer Lispers, many forms of Lisp type annotations are similar to it.
What Clojure has brought was making those ideas "modern" again.
What might be revolutionary is making more "common programmers" aware of them.
And SIGPLAN papers don't really count. A revolutionary product is not the same as a revolutionary idea. Implementing ideas that have never been productized is still revolutionary.
ETS tables are usually out-of-(Erlang-)process. You are sending messages to them to update them and query them, and those processes are each functional, so it's still functional. IIRC there's a mode where it runs "in process" with you, but it's still conceptually behind the same interface. (Which raises interesting questions about what exactly is "mutable" or "not mutable", which IMHO ultimately get best answered by Rust.)
What Erlang is not is pure. You can query an ETS table, send it a command to mutate, then run the exact same query again and get a difference response. The message passing makes things impure, even though every individual component of the system is immutable-functional. And there are some other impure functions in Erlang as well, of course, like the functions to get the current time, but the message passing is in some sense the fundamental introduction of impurity at the architectural level.
That's how you think about it, but allowing mutation and allowing blocking interaction with processes are exactly the same, as blocking interaction with processes is the same having as continuations, and continuations alone are all you need for mutation, even if you imagine things to be immutable. Like monads, continuations are a universal effect. An otherwise pure language with continuations is indistinguishable from an imperative language, i.e., it is imperative.
Both Clojure and Erlang are functional-imperative languages, but unlike other imperative-functional languages (like ML), they have been designed with concurrency in mind, and the mutations they support are transactional (or at least atomic(.
Hyperbole much?
Source: I played for a while around 2008 with common lisp and web apps, and while the tooling (hunchentoot, elephant, etc.) was solid, my completely subjective assessment was that the community languished and it was very hard for newbies.
EDIT: Why was I downvoted? Explanations enable enhancement more than punishment... Is it for the reddit-like "source:"? I really dont get it.
You could make an analogous argument for C not being portable, since it uses an ecosystem of tools and libraries that might not be portable to all systems.
Of course, you will always have a set of points at which the language needs to call lower-level functionality, but you should keep that set as small as possible, to make the ecosystem easier to port.
And in the modern "client/server" world, you really need this, because systems are often heterogeneous, and you often need to move one piece of code to another part of the system which runs on a different runtime.
It would be cool if Clojure was one and the same thing and then had a backend to support generic platforms - this way you would have ClojureJVM, ClojureNET, ClojureGO, whatever, with different levels of support and speed, but at least you could share the code. For example, maybe the Go version could have only :aot and write Golang sources.
That it doesn't compile to Go, that's because Go isn't a good compilation target. Besides being a subpar language that ignored the last 30 years of research at least, it wasn't designed to be a platform for other languages. If you're looking for disappointments, you aren't looking in the right direction ;-)
That is not really fair. As an example, Clojure itself is dynamically typed, which means it ignores a large chunk of research itself.
It does not. PL research is about how to construct type systems if you choose to construct them. There's plenty of research in untyped languages, too (for a recent, pretty exciting example, see Dedalus, which is the language semantics at the core of Eve).
(1) "I love functional programming! Therefore, newer languages that aren't following in the mold of Haskell are conceptually antiquated."
... yet...
(2) "I don't care about static typing. Therefore, it's cool to ignore the trend of most major languages moving in that direction over the past decade."
Then of course the Rust and Swift guys would tell you that Clojure is an anachronism for relying on garbage collection. Etc, etc...
All of these trade-offs, at the level on which they're commonly discussed on HN and other forums, are matters of subjective preference. And that's okay. Disrespecting other communities for their subjective preferences, while trying to give it the objective veneer of "You've ignored the latest 'advances'!", is just pretentiousness.
But that doesn't mean that you can't discuss the tradeoffs, or that they're just subjective preferences. Someone who really understands Rust would never say that GCs are an anachronism, as they would be very much aware of the cost Rust pays for the ability to maintain safety when a GC can't be used. But that's not a subjective preference, either. A language like Rust knowingly sacrifices convenience and development speed to be able to target certain kinds of applications.
I assure you, we would very much not. (The Rust team, anyway. I haven't seen that kind of nonsense out of the Swift team either, and it'd make even less sense, as Swift is technically garbage collected.)
Please. They didn't ignore the research they just decided against it. You might say that they were paying more attention to the last 30 years of experience.
I get that that the inventors of Go are respected people, but even they can mistakes.
Can beef that up with some arguments? The creators of Go are not ignorant, they just decided consciously to create a language easy enough for recent graduates to be productive quickly.
From a science point of view, the only valid reason why clojure cannot compile to Go is that nobody cared to implement that.[1] Well, either that, or the people who considered doing that realized that compiling a programming language to a Chinese board game is equivalent to using an abacus and abandoned the idea .... ;)
Anyone is free to create a native AOT compiler for Clojure.
In fact many attempted to do so, but have given up due to the effort it means bringing a full eco-system up to speed to what Clojure already enjoys in JVM, .NET and JS runtimes, libraries and tooling.
Specially in quality of generated native code and GC implementations.
It is not pure, but it is much closer to this than other lisps and it is immutable by default with efficient functional data structures. CL and Schemes are not this way.
Data is a first class citizen of the language: data literal is part of its syntax, and it uses powerful persistent data structures behind that.
Programming with Clojure is what has made me realise that data is really what matters after all. None of that FP or OO discourse should deviate us from that reality check that computing is all about data-in/data-out. Pull the plug and/or battery of your computer and see what remains next time you power it up.
So yes, Clojure may not be revolutionary in itself, it does rely on the shoulders of giants. It is however setting a new standard in terms of being successful in bringing together a very well thought out set of features and philosophy to bring the focus of programming back towards the real complexity, instead of the accidental one created by how we think.
I wrote Clojure full-time for a few years. I was lucky to do so and get paid to learn such an interesting language and paradigm of software development.
Aside from the points you mention, of which I agree, there is one other point I took away from the experience that many would disagree with: I really, really missed static typing.
So that's the main reason I don't use Clojure as much any more and went back to other languages with a different model of typing. But I learned so much and it changed the way I work in other languages.
The only thing special about Clojure is that it was marketed well and became popular.
Other reasons might include the fact that the CL ecosystem in late 10 years ago was light-years behind what it is now. And of course people have an irrational repulsion to some characteristics, like the reader upcasing all symbols by default, which has caused me 0 problems other than the fact that I though it was weird in the beginning.
No disrespect to clojure, it probably got a lot of people interested in common lisp and scheme as a result of existing, but that's my view of things.
This is kind of oxymoronic - because those things make it less of a lisp. And to be frank, if you don't think
(vector 1 2 3)
is readable, then I don't think you really get lisp.Protocols
A greenspunning of OO features with a different name because Hickey doesn't get OO (probably never made it through to the bit SICP where you implement objects, or read the "closures are a poor mans object" koan).
90% of the rest of what you list can be found in in various lisps - often all in the same place (racket, common lisp).
In fact, traits related OO research goes back to Smalltalk variants and Lisp Object Systems.
https://en.wikipedia.org/wiki/Trait_(computer_programming)
"a trait is a concept used in object-oriented programming, which represents a set of methods that can be used to extend the functionality of a class."
Then follow on protocols as an idea of generic interfaces
https://en.wikipedia.org/wiki/Protocol_(object-oriented_prog...
Then travel back in time to 2003 and read the European Conference on Object-Oriented Programming (ECOOP) paper "Traits: Composable Units of Behaviour" for a possible view on traits long before Rust was born.
The way programming languages do information hiding, polymorphism, method/function dispatch, data modelling is also part of OOP and there are several ways to combine them.
OOP is so much more than just plain objects and classes.
In fact, the same concept exists in Haskell, where it is called "type classes." (In this case, I think the adoption of OO terminology is harmful to comprehension, rather than helpful). Are we to believe that Haskell is object-oriented also? Is there a language with polymorphic abstraction that is not object-oriented in your formulation?
And given time on the weekend I might try to find out the talk given by SPJ about this very issue.
Polymorphism and dynamic dispatch are part of OOP.
EDIT: Found Simon's talk
Adventure with Types in Haskell, part 1 and part 2:
https://www.youtube.com/watch?v=6COvD8oynmI
https://www.youtube.com/watch?v=brE_dyedGm0
At 1:01:01 on the first lecture he discusses how Haskell relates to OOP in regards of subtyping and generic polymorphism and how although different on the surface they share those CS concepts in their own ways.
https://www.youtube.com/watch?v=6COvD8oynmI&feature=youtu.be...
What is an example of a language with polymorphism you do not consider to be object oriented? I'm not really interested in being linked to media I've already seen, I'm trying to suss out what you think object oriented means. As far as I can tell, it means "polymorphism," and well - yes I think polymorphism is a great idea, but I don't think its what most people mean when they say "object-oriented."
(Also, if Haskell type classes are interfaces, then so are Rust traits. They have the same semantics. But you've already said that Rust traits are traits.)
Rust traits are easily modeled in UML, just to add another point to it.
Better stop here then.
Not Object Programming. I'm not using any objects when I write Rust code, even if I'm using concepts from OOP. But yeah, we've both made our point.
(As an aside: I am the author of several Rust trait RFCs & I have read "Traits: Composable Units of Behaviour," though "How to make ad-hoc polymorphism less ad-hoc" is more relevant to Rust. Your smugness about this toward the other poster is not appreciated.)
I don't see him being smug at all. Is it smugness to suggest reading material to someone when they've shown ignorance of a topic? People do that to me here often from time to time and I don't interpret it as "smugness".
As for the other poster, sorry if it appears like that. I did not offended anyone and provided information where to read more about trait systems.
HN comments are not big enough to provide an history of OOP systems, their similarities and differences.
I might be tempted to say that object-orientation has no explanatory value - "it just means polymorphism!" - but I think what's more accurate is to say that its explanatory value operates within a distinct discourse from the discourse I am familiar with.
I regard rusts structs + traits as an object system. But I understand why they chose to not mention objects at all - they don't want to conjure up images of Java boiler plate and heavy mutation, which is sadly what it means to most people now.
I don't regard them as an object system because they are à la carte, while objects tie data and behavior together
I feel like data and behaviour is very much tied together in a rust struct. With the right visibility modifiers it can be completely opaque - it's literally a black box you are sending messages to. The methods are attached to the object in my mind.
But I am by no means a rust expert. I'm curious is to why you think the data and behaviour are not tied together.
A brief look at this site for the other "OOFeatureButNotOOBecauseItHasADifferentName" finds this gem
Clojure multimethods are a simple yet powerful mechanism for runtime polymorphism that is free of the trappings of OO, types and inheritance.
This guy just doesn't get it and I am tired of him being held up as an authority.
those things make it convenient lisp.
If you find real LISP code unreadable because it doesn't look like javascript - because you can't tell when your sequence is a linked list or an array when there's no curly braces - I suggest learning to read and write LISP code and understand how LISP works. A real LISP I mean, not clojure.
Again, other LISPs have data structures aren't from linked list. A complete myth that that they only use linked lists.
Syntax is something novices judge the language by. Their criticism is not always valid, but if language can make concessions that don't undermine it's core values but lower the learning curve - there is literally no reason to not make these concessions. No reasons apart from elitism and purism that is and those are just plain stupid.
Clojure is great example of lisp that is easier to grasp (one of main reason being sane use of data literals) but still remains lisp all the way down to it's core.
I mean LISP syntax is objectively much more simple. I think if you were to sit programming novices - with no pre-conceived notions - infront of an s-expression language and an ALGOL looking one, you wouldn't find much difference on which is easier to learn.
I genuinely think people have difficulty letting go of stuff when they learn LISP. When I first started I thought all the parens were silly as well, and I thought stuff like sweet-expressions [1] were clearly the way forward and it was only those stuffy old elitist scheme programmers who couldn't see it. But over time I saw that the simplicity and regularity of s-expressions made it worth it.
Clojures awkward smashing together of javascriptish syntax into LISP reminds me of nothing so much as training wheels on a bicycle. Sure I suppose you can call those of us who ride a bicycle with two simple wheels "elitsts" and accuse of rejecting "convenience", but to be honest when I see people defending ugly literals and complicating the syntax of a LISP language, I can't help but suggesting that they learn to ride a damn bike.
yeah, exactly, it doesn't. which makes lisp elitism very awkward.
> LISP syntax is objectively much more simple
things can be too simple, to the point where it is counter productive and harmful. example - why do you need all these weird symbols to represent numbers 1234567890? seems like 1 does the job just fine. unary arithmetic is trivial - just stitch numbers together and you have addition, just repeat them X times and you have multiplication. no need for weird shenanigans with symbols changing because of trivial operations.
> Clojures awkward smashing together of javascriptish syntax
i genuinely think you have difficulty letting go of your biases. all clojure did was designate two more kinds of parens to mean something useful in a language. it's a tradeoff between being pure lisp and being easier to grasp while still remaining lisp. but i can see now, tradeoffs are hard to understand for elitists/purists.
i wonder if every time when you buy a keyboard/laptop you're ripping off those damn [] and {}. because your arguments are unreasonable enough to think that might actually be true.
> yeah, exactly, it doesn't. which makes lisp elitism very awkward.
The thing is, people sometimes use elitism as a synonym for chauvinism, which it isn't.
"Lisp is easy, everyone should use it for everything" doesn't, by itself, meet the definition elitism because it doesn't refer to some small elite group being somehow better than others.
agreed.
> Lisp is only pure s-expressions and everybody who can't read them or wants a more 'convenient' syntax are too stupid to understand it
however does meet that definition in my opinion.
That sort of statement is tech elitism, not Lisp elitism. Usually out of frustration when dealing with trolls.
I don't believe that there are any programmers who genuinely can't deal with Lisp syntax at least as well as they deal with any other syntax.
There are only trolls who lie in making that claim, and there are trolling non-programmers who tell the truth.
Simplified syntax is mostly a threat to those who hold mastery of some arcane syntax as their principal intellectual achievement: i.e. advanced newbies.
The fact that exactly the same semantics can be expressed in a syntax that lesser newbies can learn in a day is a big threat to someone who spent months memorizing some syntax, because it means something in which they take pride as a great value is actually worthless "fool's gold".
If you're a professional who does a lot of numeric work with arithmetic expressions, working in S-exps will make you grumble, but you can do it.
Lisp has those short-hand notations. There is nothing worse about 'X over (quote X).
The only thing wrong with [1 2 3] -> (vector 1 2 3) is that it's somewhat of an unimaginative waste of these [ ] characters.
The main advantages of Clojure are the libraries from JVM/.NET, having a few parenthesis replaced by square brackets and charismatic community speakers like Rich and David.
I'd argue the main advantage is the consistent focus on making pragmatic engineering decisions and the focus on building a community who are equally pragmatic.
I've got a bunch of Clojure apps that I wrote ~5 years ago that still work on the latest version of Clojure with the latest libraries. That is pragmatic engineering.
Cursive, the Clojure IDE built on top of IntelliJ, is an amazing bit of work when you consider it is written by one guy. Again the clever use of leverage.
A focus on everyday immutability and easily reasoned concurrency makes building and reasoning about medium sized applications much easier.
Etc etc.
For a language not backed by an industry titan it has done an amazing job.
Sure when you look at something like spec there isn't a whole lot of "secret sauce" - almost all of it has been done before (I remember the big Microsoft push for runtime contracts over a decade ago). Despite this I predict it will have a huge impact on overall codebase quality.
Don't get me wrong, I understand the convenience of having all of that built in, minus the crusty parts of Common Lisp, but as far as language features go, I'd say it was evolutionary, not revolutionary.
Then, yes, others existed before Clojure.
Clojure is just another lisp.
Lisp doesn't either. Functional programming >> immutability.
Not in the sense that it is more like Clojure than another Lisp in syntax and semantics.
if x + y == 8 { (println "we add up") } else { (println "wat?" ) }
really seems to combine syntaxes in a super-confusing manner ... The "if" is not in an s-expression, but the println call is? And there are blocks denoted using C-style braces mixed in ... I think this would take a while to get used to. :) (println
(if (== (+ x y) 8)
"we add up"
"wat"))Clojure is a language which compiles to JVM byte code, which is also the platform that java compiles to, so (as consequence of that) they can interoperate.
But I don't think Clojure was meant as a replacement for Java or some kind of extension of the Java language or some sort of CoffeeScript for Java.
Clojure is a powerful functional programming language with lots of new paradigms and original ideas - quite at the opposite spectrum of the object-oriented Java.
Although I don't program in it, my C++ coding skills and more importantly architectural skills, improved dramatically after learning Clojure.
So the title of the article is incorrect (and click-bait-y).
> x := 3; y := 5; if x + y == 8 { (println "we add up") } else { (println "wat?" ) }
though mixing C like syntax and LISP is a bit confusing. Why such choice ?
LISP --> GO-lang
I am a huge fan / user of Python (which is an interface to C) but that also did take some time to justify itself, no?