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

Would you mind sharing an example of "Working on something meaningful that pushes at the edge of my self actualization"? In my experience, work, even when meaningful, is quite separate from self actualization. I'm interested to hear how you're combining them.

I’m not OP, but I can speak to my own experience.

I am approaching 40 and in two weeks I will begin clowning lessons with a Cirque du Soleil clown. I am thrilled.

So why clown as a discipline? Something deeply misunderstood and that probably lowers my social status with people who don’t understand it? Something with zero career utility? Because to me it represents extreme vulnerability.

I’m a pretty dignified person. A lot of poise. Goofy, but restrained. If I can debase myself in front of an audience in order to win a laugh then I believe I can do anything.

If I can (figuratively) hang my ass out for all to see then I can move with confidence. If I can blow past my natural inclination to save face, or have the answers. If I can discard the emotional hangups that make me feel embarrassed then I can be the person who I (and I suspect a great number of us) want to be deep down.

I want to (constructively) tear down everything inside of me that restrains me and discover who I can really be.


Ah, thanks for chiming in with your inspiring anecdote. I realize that perhaps I interpreted "working on" as pertaining to career work, rather than just investment of effort.

Your example of clowning shows something that requires real work and, as you laid out, hopefully does wonders to improving confidence, humility, humor, and charm. I wish you the best with that! And happy early birthday. :)


I took an acting class in college and found it remarkably challenging, but valuable, to tear down those emotional restraints. I should get back into it, it’s a skill that needs to be regularly practiced. I wish you luck and I hope it’s a valuable experience for you!

> In my experience, work, even when meaningful, is quite separate from self actualization.

I guess it depends on your temperament - I am very very high in industriousness and moderately high in curiosity, but the industriousness overrides the fragmentation of attention that normally comes with high curiosity individuals.

2 years ago my hobby project turned into a company, and now I run that, so for me I can find self actualisation through work, but I imagine if I was a different temperment, where work didn't overlap so much, it would be harder for that type of person.


I am the creator of jank. I am also not interested in a flame war.

The key differentiator for jank is the seamless C++ interop, which is a problem not many people are willing to tackle, due to its scope and complexity. jank is a novel approach to this, providing incredible JIT and AOT support of arbitrary C++ libraries alongside your Clojure code, including a Cargo-inspired native build system for building your native deps along with your program (or finding them in the installed system).

For some people, there is another key differentiator, which is the amount of AI-generated code involved. My understanding is that Jolt and other newer dialects like Glojure have a lot of spunk and are exploring new ideas, given the velocity that AI-driven coding can provide. I don't see jank ever being categorized in that way.


Thanks, and thanks for the effort on jank !

Since you're here ;) : I read on the alpha doc that protocols and other part of the clojure object model are not done yet - is your goal to include them eventually, or is there a part of the lore of clojure that makes them not indispensable ?


Protocols, records, and the like will be implemented in jank. They haven't been prioritized for two reasons.

Firstly, historically, jank had a closed object model for performance, which I have blogged about here: https://jank-lang.org/blog/2023-07-08-object-model/

Over the past few years, I've been spending hammock time to find a solution to this to re-open the object model efficiently. I came up with a design this year which addresses the concerns raised in that blog post and opens up the object model, but jank today is still in a half-way state between the two systems.

Secondly, in the several years I've written Clojure professionally, I don't recall ever writing my own protocol, record, or struct. When I was first learning Clojure, I leaned on them more heavily, since I was coming from OOP land. But once I leaned into the pure Clojure data designs, the OOP side of things just stopped mattering. So, if I were to write just about anything in jank, I wouldn't intend on using these features. That alone has made them low priority for me.

But they'll be implemented. :) I'd estimate Q1 next year for me to tackle those.


> I don't recall ever writing my own protocol, record, or struct.

I'm honestly extremely surprised. Protocols seem sort of essential if you want two different "things" to exhibit the same behavior.

The whole set of immutable datastructures are fundamentally backed by them (well they use Java Interfaces but its fundamentally the same). Not entirely sure how youd implement them without Protocols

Theyre also sort of essential if you want plug-in backends for any part of your codebase.

Im curious what your go-to is currently? Do you just write multimethods and dispatch on the inferred input type?


I also rarely use multi-methods in Clojure. I just use maps and vectors and lists and keywords and strings and functions. Instead of multi-methods, I generally use a map of fns. When not writing open, extendable libraries, this is an even simpler choice which I find works well. Most of my Clojure work has been writing applications, so being able to extend in an open way is not a benefit. I'd prefer to keep everything centralized in one map.

Also, as I described above in the blog post, protocols/interfaces aren't needed to implement Clojure's object model either. They're just one approach. They're the nominal typing approach, in contrast with something like the structural typing approach, documented in the blog post. For that, we use C++20 concepts for structural typing predicates.


Prtotocols tend to be useful for the same reason as Java interfaces. For example, Ring uses a protocol to specify the contract for the adapter. So, then you can just implement it and seamlessly drop in wrapper Jetty or Undertow or whatever. https://github.com/ring-clojure/ring/tree/master/ring-core-p...


Yes! This is exciting to see. Erin Catto is such a cool hacker. Thank you, Erin, for sharing your code with the open source community.

There wasn't anything about determinism in the announcement, but I'd really love to see some more about that, too. Trying to use Unity's built-in physics to make a networked billiards game is quite troubling, when none of the clients can happily agree on what happened.


I was looking for the same thing. There is a replay mechanism, so it seems to be deterministic. But with floating point physics, not across platforms. Though -ffast-math is unsupported according to the documentation, so maybe it is intended to be deterministic across platforms? https://box2d.org/documentation3d/recording.html

EDIT: Clarified meaning about ffast-math


Ah, found more: https://box2d.org/documentation3d/md_simulation.html#autotoc... "Box3D is designed to be deterministic across thread counts and platforms."

This is absolutely fantastic!


PhysX itself (assuming Unity still uses PhysX, but any major physics engine will be the same) is unlikely to be your problem, although it is possible that Unity compiles it with undesirable optimisations, or some aggressive multithreading strategy, etc.

In any case, it's quite likely that the physics simulation is not being initialised with identical state on each instance, so the physics engine -- even if it claims to be deterministic -- cannot be expected to arrive at the same solution across instances. From the scripting layer atop Unity (et al.) you are essentially out of luck. You don't have the requisite control/access to guarantee the simulation input is consistent.

To expand on the "quite likely" variance in the simulation input, there's an unending list of possibilities, so just a couple of points: Unity is really really big and complicated. The physics engine in Unity is not primarily there to be a FEATURE: physics engine. It's a general purpose collision system, and it's fundamental to Unity's whole world/scene/components. It's always running. Stuff that has nothing to do with what you see as your simulation can affect your simulation.

My unopinionated advice is: read Glenn Fiedler's classic networked physics articles[0].

My opinionated advice is: you're making a game where the physics is the whole game. It's also a very nicely contained problem space. Write your own physics simulation. It's gameplay code. Also, typical rigid body physics engines certainly can do a billiards sim, but they aren't actually that good at it.

[0] http://gafferongames.com


I am researching for a talk on the philosophy of code, the similarities of engineering and art, and why we enjoy reading old code. This amazing work you folks have done may be an interesting tangent.

The biggest question I have for you is why you imagine we are so interested in reading these old scrolls. Surely some of it is to see whether or not, technically, we can. Surely some of it is to get a glimpse into the human expression inscribed on them. Are we looking to learn anything, or just to connect with our ancestors? I'd like to hear your take on it, both for why you think it's important and, if you know, why your colleagues feel similarly.


I wrote this as an answer to a different question but I think it applies to what you're asking as well

> Though I have an interest in Old Norse and I spend a lot of time reading Scandinavian runestones. > 90% of them are grave markers for a dead father, mother, brother, sister, cousin, etc. If I've learned anything from that, it's that people across time and space all lead lives as real and complex as anyone else's. Their joys were as high as mine have been and their sorrows as low as mine have been.

A VSauce video I watched a long time ago described that realization as "chronosonder". I think trying to understand those that came before us and why they made the decisions that they did given the circumstances they were in can help better inform us of the things we choose to do given our own circumstances.

Otherwise, I think that a lot of things are worth doing just to see if it's possible. I like to lift weights and I'm training to lift the Dinnie Stones one day; a pair of stones that are a combined ~730 pounds. The physical and mental benefits of exercise and training are well documented and great but at the end of the day I just _really_ wanna pick up 2 stones. There's nothing more to it than that, and that's ok with me.

One of the things we said a lot in 2023 was "We just wanna read the scrolls" but that slogan has unfortunately fallen a bit by the wayside as the goal and path got longer and initial hype started to fade, but I think it perfectly encapsulates why: The scrolls are there. They can be read. Why not read them?


1. Why is that a realization, are there really people who say "Scandinavians are just mechanical" or "9th century people were made out of wood"? Why would their lives be assumed not to be "real", what even is that mindset?

2. "Real and complex lives" doesn't mean "just the same as ours", mind you.


> 1 Are there really people ... Why would their lives be assumed not to be "real", what even is that mindset?

Yes, there are a very great many!

The philosopher David Gray says that most modern thinking sees our way of life and liberalism and "progress" as meaning growth and change. It implies it is inevitable, a kind of always changing improvement.

Change that has occurred is for the good and its impossible to go back. I like the ${current_year} meme where someone says "it's 2026 things have changed, sweety". The joke is funny because that's what people actually say and that they say this every year but they don't notice that they say that every year.

So the modern way of life has many people who view people in the past as not real, as figuratively made of wood, who are primitive, who didn't lead complex lives.

David Gray concludes by saying that Liberalism therefore needs to be constantly fought for, that you cannot rest on your laurels and think that humanity is naturally and inexorably progressing.

These scrolls and History as a whole challenges a fundamental psychological investment in modern liberalism.

To think of the world as always improving and evolving for the better directly opposes a kind of empathy about how people 2500 years ago are the same human beings as we are. The scrolls should humble us.

Given this.

> 2. "Real and complex lives" doesn't mean "just the same as ours", mind you.

They are more like ours than we like to imagine. We prefer to think of ourselves as improved.


OK, one of those "we need humbling" assertions. No we don't need humbling.

I reckon you motivation is the other way round from what you state. Claiming to be empathetic about how people 2500 years ago are the same human beings as we are, and claiming that others miss this, is a way to oppose those who think of the world as always improving and evolving for the better. So it serves your goal, which is to dish out a humbling to all the naughty conceited moderns.


Although advocating to have less empathy generally isnt considered good there are ancient and modern schools of thought that explicitly says that empathy can be bad.

To understand the enemy is to some extent to start to love the enemy and that's bad because the enemy is bad. The idea is that you can only have empathy for certain people.

Worth also pointing out that there's also a more modern but uncommon idea that empathy towards someone or a group may weaken and shutter their own "truth" or identity stories but this is for the moment only heard in radical academia not on the street.

Generally there's also a large amount of people who don't know what "empathy" means with the ever present confusion of it with "sympathy", endorsement and alignment.


They are like us. If you could take a baby from the past and let it grow up in our time, you wouldn't be able to distinguish it from a baby born in modern times.

If you see value in travelling to other countries and appreciate experiencing the different human cultures there, you should also appreciate experiencing human cultures from the past.

They are separated from us not by distance but by time which makes it harder to experience their culture.

So much was lost that we can only get glimpses on how lives were back then. So anything that expands our knowledge on the variety of human beings experiences is worth it.


There are three aspects of this which concern me the most: personal, open source, and business.

On the personal side, code is art, not a means to an end. Many of us love coding. For me, it's my favorite thing in the world to do and it has been that way for 20 years. That's why we enjoy going back over old game code, to see the clever tricks that people came up with. That's why we preserve code in archives, to last thousands of years. Sure, we can generate classic art, too, and it can be fun. But generating Rambrandt paintings is nothing like actually seeing the originals. And it's nothing like creating your own.

Code being art is exactly why coders are so opinionated about their tools. Just like artists are. "I only use vim and functional programming and Linux" says the coder. "I only use these paint brushes, and this type of paint, on this particular type of canvas" says the painter. People don't consider this enough, for coding, so they just say "Use the best tool for the job." But any paint brush will do, for most jobs. Any language will do, for most jobs. Why it all matters is because we care. We care because art is a form of personal expression.

On the open source side, maintainers now just get huge PRs full of slop changes. The submitters tend to feel like they're helping, but they're just wasting everyone's time. The trust landscape of contributing has been eroded. The security concerns of large changes are now more pressing than ever. The gross disregard for licensing spits in the face of both the nature of open source and the actual legal ground on which LLMs try to stand. And then so many projects trying to grow end up getting vibe-coded weekend projects as competitors and people actually think they're comparable. For the non-trivial cases, they're not, because of the business side.

On the business side, let's take a programming language for example, like Zig. A business will be hesitant to adopt a particular technology if it's just one guy working on it. But if the technology has a community, a foundation, and a handful of devs working on it full-time, it is a safer investment. A big reason here is that the bus factor will be higher than one. However, LLM-generated code is a black box. It has a bus factor of zero. Nobody understands all of the code. Probably, nobody ever will. If there is a critical bug at a critical time, there is nobody to call. We would have to rely on LLMs to find and fix the bug, but how much faith can we actually put into this? That covers third party technology, but the same applies to first party technology.

If a small business decides to use Claude to create their mobile app, rather than hire an experienced dev, they now suffer the same black box and bus factor problem. Even if they hire a dev, but they expect the dev to finish at vibe-coding speeds, we end up with the same problem.

---

In short, vibe coding removes everything I love about my favorite thing to do. It also creates heaps of blackbox code with no ownership, beholden to proprietary tech which is only getting more expensive. Why would I like that?


Once you learn Clojure's syntax and semantics, you're no longer bound to the JVM. There's ClojureScript (JS), ClojureCLR, ClojureDart, jank (C++), Basilisp (Python), babashka (SCI), and many others. This means that, if you don't know Java or don't like the JVM, you can likely use Clojure wherever you already feel most comfortable.

For the most part, any Clojure code which doesn't use host interop will work on all dialects. Clojure also has support for conditional code, depending on the current dialect.

This is one of Clojure's superpowers.


As someone who loves Clojure, I wonder about the real portability across host languages. Do you have experience with any of these other dialects? (beyond the obvious CLJS & Babashka?)


I am developing a test suite for portability of clojure.core across dialects. You can find it here: https://github.com/jank-lang/clojure-test-suite

Currently, we have Clojure, ClojureScript, ClojureCLR, Babashka, Basilisp, Phel, and jank running the test suite.

I have only used Clojure, ClojureScript, and Babashka in production. But I am the creator of jank.


I’d like to say thanks for that - I’ve been using it on my IR version of joker: https://rcarmo.github.io/projects/go-joker/ and it’s been very helpful to pin down bugs.


I build and maintain Portal, which runs on multiple platforms including: Clojure, Babashka, ClojureCLR, ClojureScript, nbb, joyride, basilisp and soon jank. The main thing that's different per platform is the os/fs/http/ws libraries but the runtime state and serialization is all the same and reused across all platforms. Also, recently I was able to get most of Portal's reagent viewers, which were designed primarily to run in a browser via ClojureScript, running on the JVM for Server Side Rendering. Clojure is the most portable language I have ever used!


I am learning Clojure this week, and my test project is a calculator / unit convertor [1]. I wanted it to run in the CLI and on the web, so it targets several hosted platforms: Babashka / JVM / ClojureScript. It's a single code base written in cross platform .cljc files. I already have about 250 tests written for the abstract calculator API, run as a test matrix across platforms, so the project is already in a good place for testing a new runtime.

I just learned about basilisp from the parent comment, so I asked Claude to add Python support to the same .cljc files I have, and we finished the port in about 30mins, and then fixed Python specific test cases for another 30 mins, but now all of the existing tests are passing. That's impressive in several ways.

Portability is achieved by testing. You have to put the platforms you want to support into your test harness, and the earlier the better. A calculator is purely functional, so this is a fairly straight forward port and really easy to test for. I'm not sure about larger projects, but it seems like there is something seriously right about Clojure's design that makes this easy to do.

[1] https://github.com/EnigmaCurry/calc


for JS there is also Squint which is a light-weight ClojureScript dialect without the Google Closure Compiler


indeed, light-weight means you just add a <script> and you're off to the races.

There's also nbb if you're targeting node https://github.com/babashka/nbb


> babashka (SCI)

Correct me if I'm wrong, but isn't babashka's "host"... um.. "native", for lack of a better word? It's compiled with Graal VM native, no?

Yes, there is SCI (Small Clojure Interpreter) in the middle, but that's beside the point, no?

https://github.com/babashka/babashka

https://github.com/babashka/sci


Babashka's interop is with Java, since Babashka uses a Graal-compiled version of the JVM. It's still the JVM, just baked down.

This is different from interop with the native world. It's different from the host runtime actually being native, rather than a baked down version of a whole VM.

Graal's native images blur the line between the JVM and native, I would not say Babashka has a native runtime. Perhaps borkdude would disagree. Might be an interesting discussion.


Look at the latest babashka release https://github.com/babashka/babashka/releases/tag/v1.12.218

What do you see in Assets? Native executables, specific to an OS + CPU architecture combination, like Linux + AMD 64 or MacOS + AArch 64.


As another said, jank is not replacing LLVM or LLVM IR. We still use LLVM IR! There is a diagram here which shows the pipeline: https://book.jank-lang.org/dev/ir.html

The main thing is that we just use our own IR first, to perform optimizations with contextual data which is gone by the time we get to LLVM IR. That's also why these optimizations are not practical to write in LLVM, since by the time we get to LLVM IR, we're too far separated from jank's AST with the high level semantics of Clojure.

So we just add an intermediate step. Once we have jank's AST, turn it into our own IR, do some optimizations on it for things that LLVM won't be able to see, and then hand it off to LLVM to do the rest.


Ahh OK, makes perfect sense, and interesting that that IR compiles to C++. Thanks for the info!


The first three paragraphs here are on point! jank's IR passes will not worry much about things like load/store optimization, register allocation, inlining C++ functions, etc. These are in LLVM's domain. We just worry about the Clojure side of things. Polymorphic math is intense, but we do our best to avoid the extra work by unboxing whenever possible.

> A future optimisation might be to specialise for unboxed types: far more potential speed improvement over pointer tagging, and IMO quite amenable to analysis with the Jank IR

All of these math functions are templates with four specific categories:

1. Object and object

2. Primitive and primitive

3. Primitive and object

4. Object and primitive

We handle the difference between typed objects (like integer_ref) and type-erased objects (object_ref) as well. This template then gets inlined, which is exactly what the last step of the benchmark optimizations (adding annotations) ensured. The return type of these functions will prefer primitive types, rather than automatically boxing. jank's analyzer tracks all types used, at compile-time, and supports automatic boxing. This means that we're already using the most optimal primitive math whenever we can and that it will indeed inline to just an operator call when working on two primitives, or two typed objects, or a combination thereof.

You can see the code for this here: https://github.com/jank-lang/jank/blob/29c2adb344526d26c8e82...


Thanks for the response. I really like the measured, evidence-based approach you're taking to this work.

I have the wrong CPU architectures for pre-built jank packages (x86 mac, aarch64 linux, the exact opposite of 'normal') so I haven't actually looked at what it produces, so my last paragraph was pure speculation. I appreciate the detail you gave!


I spoke with a couple Clang and LLVM devs about MLIR when I was doing the original design for jank's IR. The general consensus was that MLIR added a great deal of complexity on top of designing/implementing an IR and nobody was confident it was actually worth the effort. Since I knew exactly what I wanted, I just built that.


Your custom IR is above LLVM’s IR, correct? Is it like SwiftIR then? Maybe you could add a paragraph or two going through that design decision.


jank's custom IR is completely separate and unrelated to LLVM IR, aside from both of them being SSA-based IRs. We go from jank's AST into jank's IR into C++, which we then give to Clang compile into the LLVM JIT runtime. So LLVM IR is used in the pipeline, but we don't touch it directly. More info on that, and a diagram, is here: https://book.jank-lang.org/dev/ir.html (which I linked in the post)


Hey lemming! You're right, which is why it should be used sparingly. Since clojure.core is compiled (on the JVM) with direct linking, reacting to var changes isn't an intended concern, since they're not going to work properly throughout any clojure.core code using that var. This makes it a good candidate ns for inlining things. But users shouldn't just be doing this for their normal application vars without giving it due consideration.


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

Search: