A C macro with literals that lacks referential transparency:
#define MULTIPLY(x, y) x * y
int result = MULTIPLY(2 + 3, 4); // 14
Not knowing what something means does not make it bad, which is what I'm assuming you meant given how you phrased your sentence.
Having a shared language of patterns and problems that occur in programming is a good thing. Ridiculing such terminology on the basis of "that group of programmers sure are weird" is pointless and counter productive.
somehow i also never got the idea around these languages like lisp. I remember i studied them in school - but i quickly forgot and never got around to relearning it.
It took me probably 5 years of writing Clojure before it clicked. Once you get used to structural editing and repl driven development, it’s really hard to go back to syntactic languages.
It’s kind of like in treesitter style editing, where you can “swap these two arguments,” “select this function,” “wrap this in a try block” with a single keyboard command… but way more standardized and granular. Plus with the ability to execute anything you highlight
All that and then you realize you can store code as data (since it’s just a data structure) and run data as code.
I think most programmers don’t realize how arbitrary the difference is between code and data until they get used to using LISP.
Spot on. For me, it clicked with Common Lisp, 15 years after I graduated from university. Now, Clojure is my daily driver. And it’s extremely difficult to explain to people. I’ve gotten to the point where I don’t even try. You’re right about all the things you mentioned. Once you discover structural editing, everything else seems primitive, on the level of cavemen playing with rocks. But it’s not just one feature that makes Lisp better. It’s all of it which interrelates and creates a powerful synergy (I hate that word, but in this case it’s appropriate) that just isn’t matched by anything else. There are other languages that have a similar vibe, notably Forth and Prolog, but they are often misunderstood, too. Honestly, that’s my real test of whether someone is a senior programmer: do they understand and at least have an appreciation for these languages, even if they don’t program in them everyday.
The idea is that instead of having to learn tens of different syntactic constructs with subtle and often arbitrary differences, you just have parentheses and use them to build everything.
This is such a undervalued benefit, once you've learned s-expressions, you can basically learn a bunch of languages without having to learn completely new syntax. It'll be slightly different, with different idioms and names, but a hell of a lot easier than doing the same across every "It's like C but 50% of the syntax is different actually" language out there, which is most of them.
Is the syntax really the stumbling block for most languages? Would Rust's lifetimes or Swift's isolation rules be easier if they used more parens? Are the scoping rule differences between Emacs Lisp and Scheme easier to comprehend because the syntax is similar?
Yes, a commonly occurring stumbling block for me is trying to use one language's syntax while actually programming in another, especially when it comes to all the Algol/C-like language, I probably mix things on a daily basis.
The concepts would be easier to grok up front if they just used normal function calls instead of "And now for this special syntax that only exists for this particular feature" which just adds more things to remember, instead of just the concepts themselves.
well sometimes you get complaints in particular languages that someone has written code like they are a Java programmer, or their code is not rubyish enough, or pythonic enough, and so on.
So often people coming from one linguistic syntactical style express themselves in that style which makes their code in the new language less understandable or maintainable.
Yes it is, because as soon as programmers step out of the most basic language level (which is kinda similar in most mainstream languages) there's a bunch of wildly different concepts, with wildly different ways of writing them. Writing them in isolation might be manageable, but it's combining them effectively that gets hairy very quickly, unless one is very experienced in said language. But then, translating that to OTHER languages becomes a bar that is too high!
The kind of subtle difference I’m talking about is that in C, you have to put a semicolon after struct {…} and do {…} while (…), but not after other curly brace constructs. What would be the analogue in Janet?
The first one is pretty C-specific and for example doesn’t exist in Java. Similarly for the second one, the reason is that `while` is used for two different constructs, which for example isn’t the case in Rust. These are just accidental complexities stemming from unfortunate design decisions in C. Having a richer repertoire of syntactic constructs doesn’t by itself imply such complications.
My point was, replacing n syntactic constructs by n functions or macros doesn’t reduce the cognitive load of having to know how each construct works. To the contrary, one can argue that everything having the same syntactic form makes it more difficult to distinguish different classes of features.
> The first one is pretty C-specific and for example doesn’t exist in Java.
It was just an example, most languages have quirks like this. I don’t know about Java, but in Rust you have the turbofish operator, whose necessity stems from using the less-than sign as both an operator and a delimiter.
> My point was, replacing n syntactic constructs by n functions or macros doesn’t reduce the cognitive load of having to know each of them.
The difference is that if you don’t know a function/macro, you can just read its documentation. If you don’t know a syntactic construct, where do you look?
Another advantage is that if you want to create new functionality similar to existing language features, it won’t stick out like a sore thumb. For example, you could create an until loop:
(until (window-should-close)
(draw-screen))
# is equivalent to
(while (not (window-should-close))
(draw-screen))
In Rust, it would have to look completely different from a while loop:
until!(window_should_close(),
draw_screen());
// is equivalent to
while window_should_close() {
draw_screen();
}
Probably depends on whom you are asking. For me the essence is (1) having functions or procedures as the basic building blocks, not classes. (2) Having all the utility and higher order functions you need to deal with the functions and procedures first idea. (3) Having a very powerful syntax, that allows great semantic editing and is never ambiguous. Oh and can actually be extended in useful ways, without having to wait for a committee to decide upon "the one syntax to rule them all".
> studied them in school - but i quickly forgot and never got around
Because industry lied to you, promising "simplicity and riches". The industry didn't just overcomplicate programming. It institutionalized the complication. Why? Because complexity is a moat.
Complex frameworks need certified experts. Certified experts charge more. Companies built around expertise need the complexity to persist. So the complexity gets marketed as sophistication.
They've promised: "Java/C# will get you hired anywhere", but you're hired to write xml (these days yaml). "OOP models the real world", they said. The real world doesn't have abstract factory visitors. "Design patterns make you senior", but you only learned workarounds for language deficiencies. "Learn the framework, get the job". Framework dies, you start over. "Specialization is valuable". you're now hostage to one ecosystem.
A programmer who understands fundamentals is dangerous to this system. The fundamentals:
- a function transforms input to output.
- composition builds complexity from simplicity.
- types describe what's possible.
- effects should be explicit.
And then you realize that Lisp is the skeleton key. All that above is Lisp, or came from Lisp. Every language is either: Lisp with different syntax, or C with different syntax, or arguing between the two.
If you learn Lisp, you don't learn a language. You learn what languages are. You're no longer a consumer of a programming language or two, or a few. You are native speaker in all of them.
Pretty straight-forward, as the world as we perceive it is made of objects with attributes, interacting with each other via their methods. OOP easily fits the brain of the average person in the street.
Of course easier to explain the "strategy pattern" to a florist, instead of saying "imagine a function that takes a function". Who the hell understands functions? Such a mind-bending concept, literally nobody really knows how they work. Einstein famously complained about it. Too bad he didn't know OOP - would've been so much easier. I couldn't grok general and special relativity for so long, thank god I've found Java - it made it so much easier. I don't know what Persian mathematicians been smoking in 12th century to come up with this utterly fucked up idea of a function. And fuck Leibniz as well.
> These lisp guys really get excited over very abstract things. If you say this to an average person on the street they will probably try to run away.
Referential transparency is a funny name for a very powerful feature which helps you understand what the program does better, it's not a deeply abstract thing. Don't let the name scare you.
You could ask "why the funny name"? Well, specialized professionals use specialized jargon, even for "normal stuff". It's unreasonable to expect otherwise. Car mechanics also have weird names for car parts that are absolutely essential for the car and not that hard to understand if they explained them to you.
I started writing a Scheme interpreter about a year ago and got pretty far. I dropped it a few months back since I got a new job.
I'm thinking of getting back and am wondering if the niche (and difficult for me to implement) features are worth it. I might be better off skipping dynamic-unwind, maybe even ripping out call/cc, in favor working on the debugability, ecosystem, performance, and package management story.
> If you say this to an average person on the street they will probably try to run away.
This is the average reaction I get any time I get the "so what do you do" question. I try to stay very vague "I do computer work" or something. Or I'll say "Oh, nothing interesting" and try to change the subject. Any more specific than that and they start looking for the exits.
Frankly, though, I think lispy community has benefited from being smaller. For example, even though the now ancient Design Patterns already warned programmers to prefer composition over inheritance, the OO programmers still created 15 levels deep hierarchies.
I beg to differ. There's just isn't "easy and straightforward" path to simplicity. We thought that explaining the world with "objects" was simple and instead of using already existing language, OOP took "objects" (an easy choice) and invented a elaborate taxonomy of "patterns" to work around the limitations of objects. Just look at this mess:
- Strategy Pattern: Interface + multiple classes + dependency injection + factory maybe. Bruh, it's just a function that takes a function.
- Singleton: Private constructor + static instance + thread safety + double-checked locking.
Bruh, it's a fucking value. You define it once. It doesn't change. You're done.
- Observer/Event System: Interface + listener registration + event loop + memory leak when you forget to unsubscribe. Bruh, tis a fucking function applied to a list (or stream).
- Decorator; Wrap a class in another class that implements the same interface. Bruh - it's function composition. You learned this in algebra class before you turned fourteen.
- Command: Encapsulate a method call as an object with execute(), undo(), history queue... It's a function stored in a variable. That's it. That's the pattern.
- Factory: Separate class whose entire job is to call constructors. Come on, it's just a fucking function.
- Template Method: Abstract base class with a method that calls abstract methods subclasses must override. It's a higher-order function.
- Iterator: Interface with hasNext() and next(), mutable state, ConcurrentModificationException. It's fucking map.
The Gang of Four book exists because Java made functions second-class citizens, so programmers spent 20 years building elaborate object scaffolding to simulate... functions. FP didn't solve these problems. It just never had them.
Yet somehow the industry likes to pretend that every programmer knows (or should know) OOP, while keep telling everyone how hard programming is.
Those who found the truth understand that there's a reason why Lisp just refuses to die and it's unlikely it ever will. At 70 years, it is still flourishing.
> The Gang of Four book exists because Java made functions second-class citizens
Why do people write silly things like this? GoF was published in 1995, the same year Java was first released, and includes neither Java code nor any mention of Java. Java had no influence on that book.
iLemming, your reply is [dead] and I don't know why. Responding to parts of it:
> Peter Norvig made this argument explicitly in 1998, showing 16 of 23 patterns are "invisible or simpler" in Lisp
The GoF book even mentions this so Norvig's presentation is a useful read, but even the authors of the book knew it was true. It's not like he added a new idea with that bit you quoted, the useful parts of the presentation were which patterns became invisible or simpler and why.
> Let's try not to nitpick on literal wording to avoid engaging with the substance, could we?
I responded to a common, but false, claim. Don't make false claims and I won't call you out for it.
You can replace Java there with pretty much any OOP language, where functions are not first-class citizens, and it will still be true. There are no "false claims" here. The main point is valid. We have orchestrated an entire industry around "objects", while much simpler abstractions have already existed. You probably just have not experienced the "true" nature of Lisp, where you can interactively change any behavior of the running program, directly from your editor, without linking, linting, compiling, restarting or even saving the code you type. The process is an enormously joyful experience, it feels like playing a video game. You probably have little idea of what we've lost and what we've gained from the industry heavily tilting towards OOP.
>> The Gang of Four book exists because Java made functions second-class citizens
That is a false claim. You asserted a causal relationship between Java and the content of the GoF book that does not exist without time travel.
> You probably just have not experienced the "true" nature of Lisp, where you can interactively change any behavior of the running program, directly from your editor, without linking, linting, compiling, restarting or even saving the code you type.
OMG. You got me. I'm so, so sorry you caught me spreading lies about your precious programming language (or your favorite book, I don't know what you're trying to protect more). Thank you from the bottom of my heart for the diligent work of protecting the truth and keeping this place free of disinformation. Please send me a DM with your mailing address and I'll send you a medal, shipping cost included.
> Sure buddy. You know so much about me...
I should have checked your comment history first before making assumptions. Please accept my apologies if I sounded patronizing. Shouldn't be an excuse for my tone, in my defense I could say: "I said 'probably'". Still disagree with you overly correcting me since I firmly believe the overall notion of my original comment is correct. Thus I won't remove my snarky, sarcastic paragraph above.
No. Why would it? While a lot of things there are universal the purpose is to support Arch Linux. If you can use it for another distro - use it. There are more important things to spend energy on then just renaming stuf pointlessly.
Go is a programming language. It’s not exactly pushing google’s ad agenda.
Your criticism of using github and discord are somewhat valid, but asking people to re-invent the wheel while they re-invent the bicycle seems like arbitrarily making up rules so everyone fails. Is there some influence you expect to leak into their platform thru github or discord?
They are standing on the shoulders of giants. There's nothing wrong with the ideals and the motivation, but it begs the question: Could Mu exist without go? could go exist without google? Could Mu exist without google?
And all of that culminates with: Could the level of technology and the internet reach the state it is today without big tech? And if not, was the price we paid to get here worth it?
> but it begs the question: Could Mu exist without go? could go exist without google? Could Mu exist without google?
No, it doesn't.
Obviously Mu could exist without Go, if Google stopped development on the language, its current state could be forked (Go 2). Lots of programming languages exist without Google's support, there are even programming languages older than Google.
go does push silly things. besides being overhyped, they block anonimizing tech when accessing package repos for example.
you dont want anything to do with google or anything they make or host. they will only do it to extract shit from you. they dont give nything dont be naive.
C is also a programming language. Unlike go it foes not depend on a big tech company for it to live.
No need to reinvent the wheel. Just use wheel that does not come with a big techh bagagge.
Maybe not their ad agenda, but certainly one of their agendas. Specifically, the agenda they have to get young, inexperienced developers prepared for specifically the software development practices they employ internally.
It was directly stated that "Go is not for clever developers" and that their target is recent graduates with limited experience. It punishes you for trying to think about what you're building and to design sophisticated software, relying more on brute force. It doesn't encourage you to reach higher.
I don’t know where you are on your career journey, but having worked with countless clients, business domains, and projects as a freelancer I value readability over everything else.
If you’re working on a greenfield project in a team of one then I suppose it’s great to get in an expressive mood and emit your code poetry from those fingertips.
It’s very different to inherit a quirky puzzle and reverse engineer a mental model from there.
What “clever” code is required to write a BBS-over-IP? 99.99% of code isn’t clever and shouldn’t be clever.
> It punishes you for trying to think about what you're building and to design sophisticated software, relying more on brute force.
Can you give an example of this? I have not written much go, so i am unable to think of a case where golang encourages brute force over sophistication?
FOSS projects have their constraints on time and usually not talent, like for-profit teams often are, so they should want the code they write to go farther.
They've explicitly stated that they wanted to discourage building abstractions, since "abstractions are hard to learn".
Concretely, this is evident in how channels and goroutines both poorly compose together, in part a result of the unsophisticated type system. It's difficult to build very generic libraries that can be leveraged as force multipliers, like the tokio-tower ecosystem does. You can do it, but it comes at performance costs or involves relying on codegen.
Google's Bazel build systems are designed around reasoning about and checking-in generated code, but the standard go tooling doesn't do this well and git workflows also don't really grapple with it well. This aspect of the design is very clearly an example of internal Google processes leaking out.
I've been writing software with Go for over a decade now so it's just down to ease of use and what I know. It's performant, straightforward, compiled. It's a no nonsense language and does what it says. I'm not the type to get into language wars. I have a tool, I use it, that's it. Thanks for the question.
Love it. What could be a good addition IMHO is to add approximate costs of the placed systems, and cost of the ammunition used during the simulation ( for both attack and defense ).
I find that hard to reconcile given what I was responding to:
"Love it. What could be a good addition IMHO is to add approximate costs of the placed systems, and cost of the ammunition used during the simulation ( for both attack and defense )."
These lisp guys really get excited over very abstract things. If you say this to an average person on the street they will probably try to run away.
reply