Hacker Newsnew | past | comments | ask | show | jobs | submit | uka's commentslogin

> But by allowing you to unquote literal functions, Janet makes it possible to write macros that are completely referentially transparent.

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.


> very abstract things

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.


Thank you for the lesson. Very productive of you and on point.

Now if you relaxed just a little bit - the world would be much nicer place.


you ever try to explain object oriented programming languages and their benefits to the "average person on the street"?

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.


> Would Rust's lifetimes or Swift's isolation rules be easier if they used more parens?

For me, certainly. But it's not a matter of adding parens, it's more removing extra syntax.


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!

That just moves the subtle and often arbitrary differences to the functions and macros you use.

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".

> can actually be extended in useful ways

I just made a library with [query syntax](https://codeberg.org/veqq/declarative-dsls) over various data structures a la sql:

    (import declarative-dsls/dataframes :as df)
    (def people (df/dataframe :name :age :job))
    (df/dataframe? people)

    (df/insert! {:name "Bob" :age 30 :job "Developer"} :into people)
    (df/insert! {:name "Alice" :age 27 :job "Sales"} :into people)
    (df/update! :set {:job "Engineer"}
             :where |(= ($ :job) "Developer")
             :from people)
    
    (df/save-csv people "people.csv" :sep "\\t")
    (def people2 (df/load-csv "people.csv" :sep "\\t"))
    
    (-> people2
       df/dataframe->rows
       df/rows->dataframe
       df/print-as-table)
Printing:

    job       age  name
    --------  ---  -----
    Engineer  30   Bob
    Sales     27   Alice
It also has datalog and minikanren (with s expr, sharing the same goals etc.) And it vectorizes like APL:

    (df/v + [1 2 3] 1 [1 2 3] 1) # returns: [4 6 8]
    (df/v + 1 {:column [1 2 3] :key [1 2 3]}) # returns: {:column @[2 3 4] :key @[2 3 4]}

    (df/v * [1 2 3] [[1 1 1]
                     [1 2 2]
                     [1 2 3]]) # returns: @[@[1 1 1] @[2 4 4] @[3 6 9]]
Or you can just use [J directly from Janet](https://git.sr.ht/~subsetpark/jnj):

    (jnj/j "3 4 $ i. 10") # returns: ((0 1 2 3) (4 5 6 7) (8 9 0 1))
    (jnj/j "$" [3 4] (range 10)) # returns: ((0 1 2 3) (4 5 6 7) (8 9 0 1))
The Joy Web Framework has a cool [db query dsl](https://github.com/joy-framework/joy/blob/master/docs/databa...) too: `(var account (db/find-by :account :where {:login (auth-result :login)}))`, used for a [web auth](https://codeberg.org/veqq/janetdocs/src/commit/848dcbd8e54ad...).

From my response, bigger than the article: https://lobste.rs/s/y0euno/why_janet_2023#c_lspe6n


these little dsl's convey so much

> 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.

> the world as we perceive it is made of objects

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.


Average programmer too /j

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.


> over very abstract things.

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.

> There are no "false claims" here.

You wrote:

>> 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.

Sure buddy. You know so much about me...


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.


EEEPc ? Oh, I used to dream of having an EEEPc ... I got my degree using old C64 - had to manually encrypt packets with pen and paper to use https.

https://www.youtube.com/watch?v=VKHFZBUTA4k


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.


Ambitious. Very hard to achieve. But if we use go, github and discord for building the "anti big tech" stack - then we have failed from the start.


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.


Woah didn’t know there were programming languages other than golang. Perhaps they can switch to nodejs, Google wasn’t involved with that.


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.


> It’s not exactly pushing google’s ad agenda.

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.


> Go is not for clever developers

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.


And AI-powered chat.

Otherwise it looked very interesting, I like the idea of a flat-fee structure without subscriptions.


Why go?


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.


> First things first, why do we code? To solve problems in the most optimal way possible.

I admire the enthusiasm. As a person who codes just to solve problems in a good enough way - I assume I should stick to Rails.


I had to laugh out loud when I read that sentence.

Really? I write code to pay my bills and sometimes just for fun.

Trying to do everything "the most optimal way possible" is going to get in the way of actually getting stuff done.

"Why do we code? To prematurely optimize all the things".


Rails is awesome!


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 ).


Like the Eisenhower speech. Every missile is 10 new schools, food to feed 100 families for a year, etc.


I don't think that's what they meant.

More along the lines of comparing $200 drones to $200,000 missiles. The economics of warfare and asymmetric warfare.


I think they were making a point about the kinds of things that a society can choose to spend its tax dollars on.


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 )."


I don't follow, sorry. The comment of yours that prompted my reply was in response to this comment:

> Like the Eisenhower speech. Every missile is 10 new schools, food to feed 100 families for a year, etc.


Doing a game with ebitengine myself. Refreshingly nice experience.


Just another page counter in the 90s - a game in 21st century ...


It works great. Don't pay attention to the philosophers.

I quit twitter when I discovered it. Thank you.


To be clear, this is not intended to be a dig at the nitter team, I always assumed the software was more their focus than nitter.net


https://uka.life

To filter English posts. https://uka.life/category/english/

Often non-technical.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: