News for hackers. Stuff that matters.
Re:Swift is a more convenient Rust by tgv on Friday September 06, 2024 @06:52AM (#41464905)
Rust is not really an ML language, is it? &mut is a very noticeable difference. Calling Rust, Scala, Swift and Kotlin ML seems to be taking it too far. Scala and Kotlin even have all the traditional OOP features. You might just as well put C++ in the ML list.
Re:Swift is a more convenient Rust by tialaramex on Friday September 06, 2024 @07:57AM (#41465335)
It's not the Standard ML of New Jersey of course, like I was taught last century, but it looks like an ML to me. Rust has a sound type system, whereas a language like C++ inherits C's YOLO approach to typing.

In Rust Vec<Option<Infallible>> is just a counter. Really, that's not theory that'll just happen by default because of how type arithmetic works.

In C++ you can't even write down an equivalent type, let alone say how it would be represented, the type system blows up long before we get there.

Re:Swift is a more convenient Rust by wsabihi on Friday September 06, 2024 @11:48AM (#41467220)
I've looked for this optimisation, and while it makes sense to me (Infallible is unhabitable ==> s: Option<Infallible> can only exist if s = None ==> all values in vector must be of the same value None that is known ahead of time ==> store a counter of how many Nones are in the vector instead of each None as an entry into a traditional vec), I cannot find any trace of such optimisation, whether by reading into the bytes backing the vector (with rustc -O / -C opt-level=3 to ensure this opt is triggered), or by calling `mem::size_of::<Vec<Option<std::convert::Infallible>>>()`.
Re:Swift is a more convenient Rust by Measter on Friday September 06, 2024 @03:29PM (#41469010)
What's happening is that `Infallible` has no values, and cannot be instantiated. This results in `Option<Infallible>` only having one possible variant (None) which has no payload, and therefore being a zero-sized type.

Separately `Vec<T>`, if `T` is a zero-sized type, never allocates and has a capacity of usize::MAX. Then, when you push into the Vec, because the value you push is zero-sized, there's no allocation and no data to write anywhere. Therefore the only effect is to increment the length counter.

Re:Swift is a more convenient Rust by koverstreet on Friday September 06, 2024 @09:09AM (#41465841)
Could you elaborate? I would think Vec<Option<Infallible>> would have to be a bit vector.
Re:Swift is a more convenient Rust by zozbot234 on Friday September 06, 2024 @09:28AM (#41466006)
Infallible is a clunky name for the Never type in Rust, i.e. a type that has no values and cannot be instantiated. Thus, Option<Infallible> only has a single value, viz. None. Then Vec<Option<Infallible>> is isomorphic to Vec<()> which reduces to a length field - there's no other data associated with it.
Re:Swift is a more convenient Rust by jpc0 on Friday September 06, 2024 @07:52PM (#41470555)
Could you explain the semantics of Vec<Option<Infallible>>? What would exist in the memory pointed to by the Vec? What would be the use case for this type?
Re:Swift is a more convenient Rust by tialaramex on Saturday September 07, 2024 @06:25AM (#41472956)
The Vec itself carries four items, a unique pointer to T, a capacity, an Allocator A, and a current length. It is a generic type, generic over the type T and the allocator A.

1) lets dispense with the Allocator, for a typical Vec the global Allocator is used, so this type has no size, every Vec is talking about the same global Allocator, its state is tracked internally to itself. We need not consider this object further†

2) now lets dispense with that unique pointer. Its semantics are crucial if T had non zero size because this is why Rust knows the associated memory which is pointed to is "owned" by the Vec. However, for a zero size T this pointer is entirely unused.

3) Capacity at last actually is used, it's a machine word sized integer, so on a modern computer that's 64-bits, 8 bytes to store the capacity of the Vec, which will be the maximum possible unsigned integer of that kind, usize::MAX. It is set to this value when the Vec is created (because the size of T was zero) and never changes.

4) Length is also used, despite not needing to store any data for T the Vec is finite and this tracks how many of the zero size item are in the Vec. Thus, it's a counter.

† In C++ they use the "Empty Base Optimisation" to avoid needing space for such things, in Rust their size is just Zero and so they won't be stored.

What is the use case? Vec<T> is a generic type (Rust's generic growable array of T) so although Vec<Option<Infallible>> seems somewhat useless as a concrete type, it is likely to sometimes occur in generic code.

Example: generic code to do a bunch of potentially fallible operations and remember whether and how they failed for later summarisation may make a type Vec<Option<E>> where E is the failure type. When the operation wasn't actually fallible E is Infallible and instead of an actual growable array type we're just making a trivial counter, our summary is going to inevitably say that all N operations were successful, any code for the "List of failures" summary should even get trimmed as dead code in this case since it depends on an Infallible object and the compiler knows Infallible cannot exist.

Re:Swift is a more convenient Rust by jpc0 on Saturday September 07, 2024 @06:53AM (#41473108)
So from what I've played with Option<Infallible> in rust would be directly equivalent to std::nullopt_t and has similar semantics in vectors, ie it just increments length.

There seems to be slightly more compile time work done in Rust but using the use case you described the concept of a Vec<Option<Infallible>> can just as easily be represented as std::vector<std::nullopt_t> with very similar semantics although possibly slightly less optimisation, although I would think if it was actually used in the language extensively I would see library implementors makeing it entirely compile time just like in rust.

I don't disagree that algebraic data types are nice and that Rust has an interesting implementation of them, however this specific example doesn't seem unrepresentable in C++ using std::option and std::variant although the actual semantics relating to usage is easier in Rust.

Re:Swift is a more convenient Rust by Measter on Saturday September 07, 2024 @09:11AM (#41473748)
Bear in mind that the optimization on `Option<Infallible>` isn't specific to that type; it applies to anything that results in one possible value. For example, `Foo` in this example is also zero-sized:

    pub enum Foo {
        Foo,
        Bar(A),
        Baz(B),
        Qux(C),
    }

    pub enum A {}
    pub enum B {}
    pub enum C {}
The optimization applied to Vec also applies to any zero-sized type.
Re:Swift is a more convenient Rust by tialaramex on Saturday September 07, 2024 @07:59PM (#41477210)
How do you get to the idea that std::vector<std::nullopt_t> "just increments length" ?

I spent some time trying this out in Godbolt†, and then by hand, and then reading the Microsoft STL, and exactly as I'd assumed before I read your comment it was a growable array of one byte objects, with the type std::nullopt_t, 400 objects? 400 bytes. 4 million objects? 4 million bytes.

† Including longer than I'd like to admit forgetting that C++ silently copies large objects without telling you and so my diagnostic was actually making a new std::vector because I forgot to write an ampersand to make it a reference...

It is still possible I missed something and so I invite you to tell me what that was. But overall my thought is that you've missed the whole point and are in the same place as when C++ programmers get confused and think Empty types (like Infallible) and Zero Size Types (like Option<Infallible>) are somehow the same, which is like confusing zero (The additive identity) with one (the multiplicative identity).

Re:Swift is a more convenient Rust by pornel on Friday September 06, 2024 @08:00AM (#41465359)
Rust is its own thing, but use of algebraic data types + pattern matching and type inference makes it feel closer to OCaml than C++. The original Rust compiler has been written in OCaml, so that's definitely an influence.
Re:Swift is a more convenient Rust by lolinder on Friday September 06, 2024 @07:50AM (#41465289)
If &mut makes Rust not in the ML family then none of the languages they list are in the Smalltalk family either—there's no concept of an image, everything is in files!

It's pretty clear that we're talking about very broad families, which is okay—Rust has more in common with ML than it does with Smalltalk or ALGOL (though the ALGOL heritage is definitely present).

Re:Swift is a more convenient Rust by foldr on Friday September 06, 2024 @07:41AM (#41465219)
ML has mutable references:

https://saityi.github.io/sml-tour/tour/02-09-mutable-refs.ht...

(OCaml has something similar too.)

Re:Swift is a more convenient Rust by pjmlp on Saturday September 07, 2024 @05:03AM (#41472595)
O in OCaml is for Objective aka Objects, and ML languages do support mutable types, aka ref cells.