This is begging the question. Yes, but why did they do that over dedicated syntax?
(My personal theory is that early go had a somewhat misguided idea of simplicity, and preferred overloading existing concepts with special cases over introducing new keywords. Capitalization for visibility is another example of that.)
I'm no longer sure what you're saying. You asked why they didn't go with dedicated syntax, I listed two advantageous aspects of the chosen syntax. We know it's an overloaded comment: that's literally one of the advantages.
Well, I've been unable to follow you as well, then. Obviously if they'd used a different type of syntax (e.g. using # for annotations), those would also be compatible with the language spec, and other implementations would still be just as capable of ignoring all unknown annotations.
(Though for the record, talking about alternative implementations when discussing Go is kind of a funny joke.)
This is such a silly response when "You've gotten better at using them and know how to work around their flaws now." is right there and seems a lot more plausible.
That's how I learned a pretty important lesson about software engineering that still informs how I work to this day.
"A layer of abstraction on top of a stateful legacy system often doesn't result in a simpler system, it just introduces exciting new failure possibilities. This especially applies when the owners of the legacy system have no responsibility over the abstraction layer."
It's still true. Your metabolic system is probably not simpler after taking terzepatide. Although, just because it's not simpler doesn't mean it can't be better. I'm very glad for the C++ abstraction layer over assembly, even if the stack is more complicated than if it were just assembly
Manjaro sells itself as "Arch, but more approachable". In reality, you'll often end up with "Arch, but with additional weird package management upgrade issues that are a byproduct of Manjaro's own repositories interacting with the arch on your system."
Instead of just having to track the arch repos, you suddenly have those and Manjaro's own stuff (and own package manager tool etc.), which is another point of failure. Every new bit of technology is another part that can fail.
I think a lot of the really old school people don't care, but a lot of the younger people (especially those disillusioned with C++ and not fully enamored with Rust) are in fact quite happy for C to evolve and improve in conservative, simple ways (such as this one).
This falls under the "selling somthing" angle I mentioned. Yes yes yes, generality and abstraction are tradeoffs and higher level platforms lack primitives for things the lower levels can do.
That is, at best, a ridiculous and specious way to interpret the upthread argument (again c.f. "selling something").
The actual point is that all real systems involve tradeoffs, and one of the core ones for a programming language is "what problems are best solved in this language?". That's not the same question as "what problems CAN be solved in this language", and trying to conflate the two tells me (again) that you're selling something. The applicability of C to problem areas it "can" solve has its own tradeoffs, obviously.
OpenAI has a whole history of trying to scoop other providers. This was a whole thing for Google launches, where OpenAI regularly launched something just before Google to grab the media attention.
GPT-4o vs. Google I/O (May 2024): OpenAI scheduled its "Spring Update" exactly 24 hours before Google’s biggest event of the year, Google I/O. They launched GPT-4o voice mode.
Sora vs. Gemini 1.5 Pro (Feb 2024): Just two hours after Google announced its breakthrough Gemini 1.5 Pro model, Sam Altman tweeted the reveal of Sora (text-to-video).
ChatGPT Enterprise vs. Google Cloud Next (Aug 2023): As Google began its major conference focused on selling AI to businesses, OpenAI announced ChatGPT Enterprise.
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!
So long as you have structurally typed structs (as TypeScript does), you can do stuff like {foo: string} | {bar: string} to the same effect as type constructors if and when you actually need it.
At the same time, how often do you really need (Just (Just (Just ...)))?
Sounds like it might be an issue with your setup, considering that other people have no problems running it. Hard to tell what the problem is, but definitely a frustrating situation.
(My personal theory is that early go had a somewhat misguided idea of simplicity, and preferred overloading existing concepts with special cases over introducing new keywords. Capitalization for visibility is another example of that.)