HN user

MillenialMan

280 karma
Posts0
Comments141
View on HN
No posts found.

I don't think it's about money. Software engineer salaries are very high, and cubicles are a compromise that still saves space. I think it's because for most people, procrastination reduces output a lot more than distraction and noise, and they procrastinate less when everyone can see their screen.

The vast majority of titles in tech confer more prestige than deserved, because there's no downside to a company handing them out like candy. I don't look at it as a portability issue, the incentive isn't to be accurate to begin with. Inflated seniority is just a perk they can offer that doesn't cost them any money, so everyone offers it. Titles across the industry are meaningless unless you're calibrated to that company's levels.

The reason I'd like the construct is because it's explicit - intent (and the scope/limit of your intent) is encoded in what you create. It's clear you intend to do nothing with that name except symlink to the nested member, so the reader doesn't have to anticipate other behaviour (and can't accidentally do something else with it). Generic assignment doesn't convey the same restricted intent, and it doesn't carry those guard rails.

Really though it's a structure that only makes sense in strongly typed languages, so I probably shouldn't have used Python to illustrate the idea.

I'd like languages to have some kind of "delegate" functionality, where you can just delegate names to point to nested names without screwing around with ownership - it would just act like a symlink. The scope of that action is limited and clear (and easy for your IDE to understand), and it's explicit that the subclass is still the "owner" of that property, which makes the whole thing a lot easier to navigate.

E.g. something like:

    class MyClass:
        def __init__(self, member_class):
            self.member_class = member_class

        # Delegate one member
        delegate move member_class.position.move

        # Delegate all members
        delegate * subclass.position.*             

Then:
    a.move == a.member_class.position.move
etc.

Those rivets probably aren't modelled, they'll be reconstructed from volume information in the texture. Which is still impressive and a great way of dealing with that type of geometric detail, but it has limitations, and the engine isn't processing actual models at that level of detail.

You can still do stuff like that in UE4. Have a look at what's possible with Quixel Mixer, you can create detail like that surprisingly quickly. I'd tentatively argue that modelling tools are the real MVP when it comes to increased geometric LOD in modern engines. They allow you to add that kind of detail quickly enough that it becomes economical to actually detail rivets.

Either way, it's very cool. The crowd simulation stuff is going to be useful, current tooling there absolutely sucks outside of a few very expensive dedicated products.

I understand your point. I'm saying: the subset of problems that benefit in a performance sense from immutability is very small. The vast majority of the time, cache misses slow down algorithms. That's a perfectly reasonable generalisation and I don't really understand why you think it's untrue.

Re: change records, I believe Braid uses a historical record of absolute states, not a series of diffs. The state at a particular time is recreated from a minimal representation (a couple of arrays). That's much more efficient than throwing multiple iterations of the state in a HAMT.

In general I would agree, but a significant part of Clojure's appeal is that it's immutable by default, because that allows you to make certain assumptions about the codebase. Introducing mutable datastructures means you can no longer make those assumptions, so it potentially has much wider ramifications than e.g. calling into C code from Python.

I don't really agree. Cache friendliness is almost always a relevant factor as soon as performance becomes an issue. I get what you're saying but as I see it immutability gives you architectural efficiency and in some cases space efficiency, but rarely processing speed.

Think video games like braid

Braid doesn't use immutable data structures, it uses a historical record (and immutability would be incompatible with some of the mechanics).[1] The author of Braid is actually quite famous for his dislike of functional languages and immutability. He doesn't even like garbage collection because of the overhead it introduces.

Interestingly, he was talking about data structures for codebase representation (in the context of a compiler) a while back, and someone mentioned HAMTs. I'm definitely curious if they would work well there.

[1] https://www.youtube.com/watch?v=8dinUbg2h70

I understand the point, I'm not arguing that you can't do that or speed up your code by doing that.

Python is also slow, but you can still go fast (in some cases) by calling into C libraries like numpy - but the performance is coming from C, not Python. Python is still slow, it's just not an issue because you're only using it for plumbing.

But Clojure is immutable-by-default, that's the point of the language - it gives you various guarantees so you don't have to worry about mutability bubbling up from lower levels. In order to wrap your heavy path you have to go outside the Clojure structure and sacrifice that guarantee. You do lose structural integrity when you do that, even if you attempt to insulate your mutable structure. The system loses some provability.

You're right - I missed that, the author does mention arrays having better access characteristics, although he doesn't really explain why HAMTs specifically are slow.

How does Clojure's HAMT avoid fragmenting over time?

Clojure standard library works on arrays just fine, as demonstrated in the article.

Right, but then you don't have immutability - so you lose all the guarantees that you originally had with immutable-by-default.

Yes, this is a general problem with functional data structures. They have to be fragmented in order to share data. There's also the more nebulous issue that they encourage nesting to leverage the architectural benefits of immutability, which is a complete disaster for cache friendliness.

Replacing the critical path is an option, but that only works for numpy-style situations where you can cleanly isolate the computational work and detach it from the plumbing. If your app is slow because the inefficiencies have added up across the entire codebase (more common, I would argue), that's not an easy option.

The biggest performance issue Clojure has, which isn't mentioned in the article and is fundamentally unsolvable, is that it misses the CPU cache - a lot.

The data structure that drives the immutable variables, the Hash-Array Mapped Trie, is efficient in terms of time- and space- complexity, but it's incredibly CPU cache-unfriendly because by nature it's fragmented - it's not contiguous in RAM. Any operation on a HAMT will be steeped in cache misses, which slows you down by a factor of hundreds to thousands. The longer the trie has been around, the more fragmented it is likely to become. Looping over a HAMT is slower than looping over an array by two or three orders of magnitude.

I don't think there is really a solution to that. It's inherent. Clojure will always be slow, because it's not cache friendly. The architecture of your computer means you physically can't speed it up without sacrificing immutability.

Malaria vaccines are more effective than covid vaccines. Malaria kills a lot more people than covid. Why do you buy sushi instead of malaria vaccines? Relative to the problem I wouldn't consider that a sacrifice. Doesn't matter, I'm still going to buy sushi.

I get where you're coming from but people are just selfish with money, it is how it is.

Treating men who hire prostitutes with respect is kind, but not necessarily honest. More or less a requirement is that they not care if the person they're having sex with hates it. They're a distinct class of people and not reflective of all men.

I'm honestly not sure how I feel about it. I don't like the weird denial about that aspect of the transaction. It makes it difficult to trust the rest of her writing.

My point is that he's trying to shoehorn the "Love Languages" framework onto that situation, because the model is designed to encourage you to do that - it's the same thing that makes it sell. You shouldn't dismiss that as a coincidence, it's not as simple as divorcing that from the legitimate insights. The framework is designed to be a brain worm.

Here's a question: you like the framework. Have you ever seen a specific relationship be saved by it?

I don't mean this disrespectfully, but your comment is a perfect example of someone falling into the trap I was describing. If someone's using you, they don't love you. They won't love you. It doesn't matter what their "love language" is - giving them the thing they're looking to extract isn't going to help, it's just going to get you exploited.

Plenty of it has a point - so does Cosmo. The problem is that it's a psychological model written primarily to be sold. You're welcome to put your trust in that, but I think that's a mistake, and the way that type of stuff usually hurts people is that the model being peddled cuts off deeper understanding of human relationships.