HN user

comma_at

167 karma
Posts5
Comments44
View on HN
  Location: Slovakia (GMT+1)
  Remote: Yes
  Willing to relocate: No
  Technologies: Clojure, Docker, Common Lisp, Bash/Zsh, Python ...
  Email: petern@riseup.net
Résumé/CV: https://drive.google.com/file/d/1YzYDnSo-u823VNVIljVHH6vt8cd...

I am currently a core maintainer of Electric Clojure (https://github.com/hyperfiddle/electric), a full-stack, reactive, differential language we use for building rich, dynamic UIs. Most notably I developed the last 2 generations of our compiler and pioneered the UI composition pattern we use today. I work with Clojure for 7+ years, but also did a lot (4y+) of infrastructure work before - Docker, Kubernetes, ELK stack, Kibana and more. I worked in many other languages. I am a systems-level thinker who derives solutions from first principles. I am looking for a new challenge.

If the problem fits into the limited local resources, if there's no syncing required, no login, no multiplayer, ... Sure, do it. But don't pretend this solves all business cases.

Instead of doing the side effect you return a description and let the framework handle it. E.g. you don't call `transact(db, data)` but return `["transact", db, data]`. Now your function is pure. The framework will expect you to provide the transact handler, e.g. as `register_handler("transact", (db, data) => {..})`.

Personally I'm not a fan of this abstraction (another layer of indirection). I'd rather take a `transact` function as an argument.

libmill's goal was to be as close to Go as possible. If you look at it in that light, it's an accomplishment.

Then came libdill, which created the whole "structured concurrency" movement and brought new concepts to light that are now being replicated in python, kotlin, java...

At a bare minimum your code might have different behavior. Your `run! deref` will wait for each future one by one. What if the last one threw an exception while the others are running? You'd probably want the other tasks to get canceled immediately. I'm not sure what Executor.close() does exactly, but in theory it could do this for you automatically. Not something I want to write by hand for sure[1].

In Go for example, I don't remember having to clean up fibers manually.

And that is awful if you think about it a bit. There's no composition happening, your go block just goes off somewhere without you having any control of it. It's like goto, only it forks first and never gives back the process handle[2].

[1] https://clojureverse.org/t/missionary-new-release-with-strea... [2] https://vorpus.org/blog/notes-on-structured-concurrency-or-g...

What’s not great is loading the entire closure VM environment into my browser

There's no VM in clojurescript, it compiles to JS, it is tree-shaken and heavily optimized and minified through Google's Closure compiler.

resulting in the software running (in this case) 50x slower

The speedup is not a result of abandoning clojurescript, it's from moving from immutable data structures to mutable arrays and primitives. The same can be done in clojurescript or javascript.

I think this is a common misunderstanding, that's why I'm reacting. Nobody claims immutable data structures to be the silver bullet. Computation-heavy parts need to be done in low level code and with primitive types.

This is all good and true, but it's looking at the problem from the Linux distribution's perspective. The user wants a working application. Something like AppImage allows a small team to distribute a working package for every distro. Now imagine that team of 5, working on their app, packaging it for ubuntu, fedora, arch, rhel, ... It's just not possible.

What would solve this issue? A common package manager and central repository, across all Linux distributions. Then the small team only needs to package and ship to one repository, in 1 format.

it's just not worth learning steno if you mainly do programming

I think this will be better answered by someone who has crossed that bridge than you simply jumping to that conclusion with no experience or data to back up your claim.

To balance the views, Mirabai, the person who started this project, does live transcription in vim and uses it for editing the notes as well. Ted, one of the lead developers, uses steno daily for programming. Emily, another user and plugin developer, has developed dictionaries to help with symbolic input and modifiers (e.g. ctrl+shift+x). There are plugins for changing case (camel, lower, snake etc.)

Learning a steno system is similar to learning a new spoken language - it takes time, and the time it takes differs based on the time you invest daily, personal experience, type of study... Some have reached 100wpm in 2 months, some take 2 years. As a reference number - to be a certified stenographer you need to pass a test with at least 225wpm with 99% precision. The classes take 2 years, I think.

Being a pianist might be handy, but you'll still need to practice a lot to see progress.

https://danluu.com/productivity-velocity/

Docstrings, writing documentation, talking to colleagues on Slack, asking questions on stackoverflow, writing mails, browsing, working in the terminal. We spend a lot of time writing. How much time could one save by e.g. doubling the speed?

Another aspect is of the working memory - will it free your brain's resources? Will allow writing at the speed of thought allow for new/more thoughts?

I think we should explore these waters, and steno is a solid choice.

I agree, constraints often bring benefits. The question for a language is which ones to bring in and which ones to leave open. From that perspective I value clojure's choices (and don't value js every-io-is-a-callback design).

Any project of the size you mention needs technical leadership and constrained choices (for IO we use this, we do http this way..). This will be true regardless of what language you're using.

No it is not. People still reach out from stack when a dependency has updates and it's not in stack yet.

Nobody cares if it compiles together. The point is if a new feature or a bug fix is introduced in a breaking way you cannot bump your dependency and start using it, or progressively move to the new API.

The whole point of running inside another ecosystem is to reuse existing solutions. Many wrappers hide mutability and provide an immutable API. And more java libraries are being written with immutable classes.

I also failed to understand the "everything is a java.lang.Object" sentence. It doesn't make a clojure map mutable. In the end it's all just ones and zeroes, but that misses the point.

I for sure prefer to write a backend where no teammates ever introduce blocking calls.

Please note that forcing an execution model in the language will inadvertently cause headaches for some kinds of domains. Since clojure makes no wild choices the language can be ported to other runtimes (.net, js) and benefit from future runtime improvements without breaking the language (JVM virtual threads, value types).

Since the core is small and lisps are extensible, we can have a multitude of choices in libraries. So if you really like typy things you can check out core.typed, spec, schema, malli etc. If you want async you can check out manifold, promesa, core.async etc. If you want non-blocking effects handling you can check out missionary or darkleaf/effect.

Good programming practice isn't a language feature its a programmer feature.

I'll enjoy reading your production-grade brainfuck code.

A language's built-ins and idioms greatly influence what you say and how you say it. If your mother tongue doesn't have words to describe any emotions you'll have a hard time explaining them. You're talking only about the other side of the coin. Yes, people can write terrible clojure code, you need to be a good programmer to write good code. But please consider rewriting this bash one-liner in pure C (or assembly)

    grep FOO */* | wc -l
Having a language to express your domain concisely is essential in reducing code complexity, time-to-market, bugs etc.

Clojure has reached sustainable traction. There are large companies using it. There are shops that work with it exclusively. There's no need to conquer the world ;) If some users are evangelizing too loudly, well, it happens everywhere. You can choose to ignore it. And if you are curious why you can check it out and decide for yourself. No random person on HN can convince you.

If you cannot have compile time guarantees on correctness, the discipline to not break things becomes a key feature. On the other hand, if you have strong correctness guarantees, you may more easily incur some breakage (and thus actually fix things).

Yes, and the result of that is cabal hell. Types aren't there to help you break your API. Once the API is out and it has users it is rude to break them. The linux kernel is a prime example how far can you get if you don't break your users.