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

> Linux originally supported Intel without any Intel engineers even knowing it existed.

It should be noted that Intel makes CPUs, while Qualcomm makes SoCs, which include much more than just a CPU. Usually supporting the CPU is the easiest part, the rest is the issue.

That said, when device OEMs release the kernel sources, modders are able to update custom roms for a long time, so I doubt this is just a Qualcomm issue.


They update the roms while keeping everything provided by Qualcomm the same

so basically the kernel is frozen even if the android version is updated


> Consider an enum that represents a tree. Since, it is a recursive type, Rust will force you to use something like Box<> for referencing a type within itself. > > enum TreeNode<T> { > Leaf(T), > Branch(Vec<Box<TreeNode<T>>>), > } > > (You could also us Box<Vec<TreeNode<T>>> instead)

This is wrong, you don't need a `Box` here. The Rust compiler forces you to have a layer of indirection, but `Vec` already does that.


In one sense the places where the Rust is wrong don't trouble me because I already know Rust well, but in the end they do trouble me because it seems reasonable to assume the Swift is equally wrong but I don't know where and how.

For example "In fact, Swift treats enums as more than just types and lets you put methods directly on it" seems to assume that "just types" don't have methods, which I guess is what you might assume coming from say, C++ but Rust isn't C++ and so of course all of its types, including not only user-defined enums, structures and indeed unions can have methods - but also the built-in primitive types all have methods too.

    'F'.to_digit(16).unwrap() // is the 32-bit unsigned integer constant 15
Or maybe an even closer to the metal example: Rust's pointer provenance APIs get to provide a method on raw pointers which takes a closure to do stuff like hide boolean flag bits at the bottom of an aligned pointer. The fact that you're ultimately going to lower to an XOR on a CPU address register doesn't mean you shouldn't get method syntax, it's the 21st century.

> In fact, Swift treats enums as more than just types and lets you put methods directly on it

This section was fairly disappointing, that Rust requires you to put "} impl {" between the `enum` and its methods is... not really an interesting point.

I think the title of the article is... basically correct, and the high-level point that they're both languages with modern type systems, sum types, pattern matching, and so on is good, but too many of the examples were weak.


Adding on, its also a bit much to say that Swift has a good level of sugar and reference an enum of all things. Swift's union type story is so poor that, instead of properly modeling state, people to this day still use masses of optional types in their views rather than an enum because actually using swift enums and protocols is so painful.

I don’t which Swift developers you are talking to, but let the record know I don’t and use enum quite a lot. And I don’t find it particularly painful though a bit verbose at times.

I think Swift enums are really well designed, but SwiftData doesn't really support them unfortunately and Observable has problems with reactivity and enums (works on iOS not macOS I've found).

So lots of optionals might well be the better path here.


I don't think it's horrible, but I really do wish they would copy TypeScript here.

Let me do this:

    const x: String | Int
Instead of

    enum MyEnum {
        case string(String)
        case int(Int)
    }
There's an existing proposal for this here:

https://forums.swift.org/t/re-proposal-type-only-unions/7270...


It's worth pointing out that the two examples that you're writing are actually strictly different, and not just "better syntax for the same thing". (This is assuming `String | Int` works as in Python, and the second example works as in Rust.)

To understand the difference, `String | String` is just `String`. It's a union, not a sum type. There's no tag or identifier, so you cannot distinguish whether it's the first or the second string.

If this sounds pedantic, this has pretty important ramifications, especially once generics get involved.


To provide a concrete example, this bit me in a typescript codebase:

    type Option<T> = T | undefined

    function f<T>(value: T): Option<T> { ... }

    let thing: string | undefined = undefined;
    let result = f(thing);
Now imagine the definition of Option is in some library or other file and you don't realize how it works. You are thinking of the Option as its own structure and expect f to return Option<string | undefined>. But Option<string | undefined> = string | undefined | undefined = string | undefined = Option<string>.

The mistake here is in how Option is defined, but it's a footgun you need to be aware of.


I guess I just want to be able to do something like this in Swift:

    let x: String | Int
    
    switch x {
        case let value as String:
            // handle String value here
        case let value as Int:
            // handle Int value here
    }
There's one more thing about TypeScript-style union types: string literals. I think it's great to be able to do

    type Options = "option_1" | "option_2" ... "option_n"
And subsequently I could use

    let t: Options
    switch t {
        case "option_1":
            // handle `"option_1"` case here
        ...
        case "option_n":
            // handle `"option_n"` case here
    }
I think this is more programmer friendly than requiring an out-of-line definition of a new `enum`. Sometimes you just want to write some code, you know?

Hijacking your comment because this is a common point that's made on the superiority of Swift syntax against the union syntax.

At least with |, you're attempting to model the state space. You're saying "this is one of these things." You might get the exhaustiveness wrong, but you're in the right ballpark. As it's normally done right now, the Swift developer with five optional properties is modeling state as "maybe this, maybe that, maybe both, who knows, good luck." which is just worse than a bar. If you need to discriminate explicitly, add a `__kind` field!


Note that union types are not the same thing as sum types, even if they're somewhat similar. https://viralinstruction.com/posts/uniontypes/

> actually using swift enums and protocols is so painful.

In what way? My understanding is they're widely used and encouraged.


If you look at most swiftui views, there will be a mass of optionals, rather than enum cases for every possible state that the view can occupy and a state machine transitioning between each state.

If you actually try and write it all out (like go full-on and use TCA to model all the states and actions such that all and only valid states can be represented in the state types) the compiler is going to have a hard time, you're going to write masses of boilerplate, and just in general it's much rougher than zustand and expo.


You're not wrong, but I think there's a subtle way people still might get confused about `Vec` versus `Box` with the way you've phrased it. I'd argue the important characteristic of `Vec` here isn't that it's indirection but specifically that it's sized at compile time. Compared to a `Box`, it does not provide meaningful indirection around types that are themselves not sized at compile time (e.g. dyn trait objects), and storing them inside a `Vec` itself will require a `Box` or something similar.

I don't think that is true. Testing with rust 1.92

enum Tree<T> { Lead(T), Branch(Vec<Tree<T>>), }

works just fine, no superfluous Box needed.


Similarly, the ‘indirect’ keyword can be omitted from Swift example in the blog post, for the same reason. A Swift Array stores its elements out of line, so an enum case payload can be an array type whose element contains the same enum, without any additional indirection.

You don't need Box here because Vec<T> is already a fixed size handle to heap data.

A vector of boxes is beneficial if you need to move objects around. If each T is 1000B or something, you really don’t want to copy or even do true moves in memory.

Hell, even if you’re not moving things around explicitly, don’t forget that vectors resize themselves. If you use Box, then these resizes will be less painful with large objects.


Of course, the language lets you decide. I think this anti feature is actually a feature.

What's the problem is such inactive issue stays open?

Two major problems.

If a team does not have the bandwidth to fix an issue, closing it acknowledges this and doesn't leave people in false hope. Ideally with a status like 'won't fix' to clarify the situation. Users can move on and deal with the reality, perhaps even rally resources if they are in a position to do so, so the issue can be reopened and addressed. Everyone hates it when you get a 'me too' or 'the developers suck' email to a bug opened 15 years ago. The bug is making the world a worse place.

Secondly, the larger the collection of open issues the harder it is to actually triage and manage. There are plenty of projects where everyone would benefit if the issue tracker suffered catastrophic data loss. So many dangling issues in features that no longer exist or are completely unrecognizable, making it impossible to separate the wheat from the chaff. You are in a twisty maze of 30,000 issues, all of them alike. What should I be working on?

Unfortunately, people react to the first reason poorly if their issue gets closed as won't fix. They take it personally and abuse the developers. So we generally don't use won't fix, because of people being hostile. And then triage falls behind. And then you find you have an unmaintainable bug database of 30,000 open issues, un-triaged, many duplicated, unknown how many actionable. 'open' status has become the unofficial 'wont fix'. When you submit a new bug, you hope someone is watching and you get lucky and someone assigns it 'in progress' or sticks it on a task list. The bug tracker gets bypassed, with real issues going via back channels to developers. The project realizes it has a problem and makes it harder to submit bugs, in a hope they can get on top of things.


I assume the thinking is “why look bad when you can look good?”

Or a longing for “cleanliness” by just throwing things away.

Reminds of a TV show scene where doing the dishes meant using them for target practice. If you have no dishes, there is no dishes to do!


By that logic the president of the USA is also "not elected"

> For someone who does not follow the web's history, how would one produce direct evidence that the bias exists

Take a bunch of websites, fetch their robots.txt file and check how many allow GoogleBot but not others?


I find it scary TBH that we're on track to have more OpenSSL-level software.

Functional programming languages usually don't support linear/affine types, non-gc references and mutations.

Their closures are essentially the equivalent of Rust's `Rc<dyn Fn(...) -> ...>` with some sugar for expressing the function type and hiding all the `.clone()`s needed.

It's easy to get simplier results if you support less features and use cases.


Closures are pretty simple in relation to their captures lifetimes, but they do have a lot of complexity in how the lifetimes of their argument and return type are computed. The compiler has to basically infer them, and that can easily go very wrong. The only reason it works most of the time is because closures are immediately passed to functions whose trait bound specify the expected signature of the closure, but once you deviate a little bit from the common case things start to break down. For example if the bound is `F: SomeTrait` where `SomeTrait` is implemented for `FnOnce(&' i32) -> &i32` the inference will break. Similarly if you store the closure in a local variable before passing it to the function. This used to come up pretty often for "async" closures that were supposed to take a reference as input, since it's impossible to specify their correct trait bound using directly the `Fn*` traits. There are a bunch of related issues [1] in the rustc repo if you search for closure and higher ranked lifetimes.

[1]: https://github.com/rust-lang/rust/issues?q=is%3Aopen%20is%3A...


> Additionally, the intent of whether the buffer is used as “raw” memory chunks versus a meaningful u8 is pretty clear from the code that it gets used in, so I’m not worried about confusing intent with it.

It's generally not clear to the compiler, and that can result in missed optimization opportunities.


The opposite happened to me: I got a new Mac and had to fill out my Apple account billing details to download apps from the App Store, but somehow the form on both the App Store and the web page didn't work. In the end I managed to do it through the Apple Music app on my Android (!) phone.

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

Search: