5 ms·
>Dart makes Typescript look like a joke. Dart still does not even have union types, probably the best feature of TS. I would hold off on that claim for now..
by aliyfarah 6y ago
>Dart makes Typescript look like a joke.
Dart still does not even have union types, probably the best feature of TS. I would hold off on that claim for now..
- okamiueru 6y agoWhat is your main use case for type unions? I don't know typescript, but I haven't felt the dart language was not feature complete for all my uses. Is this something you cannot solve with a combination of abstract classes, and or/extension? https://dart.dev/guides/language/extension-methods https://dart.dev/guides/language/extension-methods
- oblio 6y agoLet's say you get a JSON API that sometimes returns a list, sometimes returns an object. How do you model that in Dart?
- okamiueru 6y agoYou could create an abstract class for the base response, then implement this abstract class for the two cases one where it has a list member, and one where it contains the object. Then, using the return value with something like `if (response is listLike) { }` the IDE already knows that you are scoped to having only the list like properties, and you'd get the full help of the language. Something like that, I suppose.
- oblio 6y agoVersus a sort of: my_type = my_list | my_object ? You can see why this is better :-)
- okamiueru 6y agoAll I can say is that it is certainly neat :)
- mixmastamyk 6y agoI'd always return a list. Makes the client code simpler.
- oblio 6y agoYou would. But not every input comes from you :-)
- munificent 6y agoYes, union types are really nice for data like that. But, in practice, a language's type system tends to optimize for the data structures that are idiomatic in the language. TypeScript is a heavily structural type system because idiomatic JavaScript often throws together unrelated types in this way (which makes sense when you're coming from dynamic types). In a language that is built more strongly on objects and static types, it's less common to see APIs that "return one of these, or one of these, or on Sunday one of these things". So there is relatively less use for union types. In other words, because people express unions at runtime less frequently in Dart (and other languages like Java and C#), there's less value in supporting them statically. Still some, definitely, but I don't think it's as critical of an omission as you might expect coming from TS/JS.
- c-cube 6y agoPeople build less unions because these languages fail them. Just add sum types or something similar, it's a disgrace to not have them in 2021. Static typing goes wonderfully well with them, allowing for exhaustiveness checks and all that. The "people use fewer unions in Java" argument is like saying people used fewer lambdas in Java 1.6. Build it, and they will use it.
- munificent 6y ago> Just add sum types or something similar I think you're confusing union types and sum types, which are very distinct features. SML, Haskell, and Rust don't have union types. OOP languages can model sum types already. It's mostly a question of how much the surface syntax encourages that style.
- c-cube 6y agoI'm not confusing them :-) I think _closed_ union types (the syntax `a | b | c`) are almost as good as sum types, since they bring exhaustiveness checking to the mix. They also act as documentation. Crystal is a good example of a language leveraging this feature. The OO model of just subclassing a common class is quite poor by itself. Scala and Kotlin have a 'sealed' modifier to at least recover the exhaustiveness check. Both also have ways of safely doing the case switch on the object's class and simultaneously downcasting (Java too with its recent `match` construct, afaik). Does Dart have anything like that?
- kroltan 6y agoNot who you asked (and I just now realized I'm replying to you twice regarding this OP, I solemnly swear it's not some crude attempt at stalking). But for me the main use for TS union types is to make discriminated unions, which is very useful wherever you have some form of a state-machine: type AppState = | { state: "loading", progress: number } | { state: "selecting_level", } | { state: "playing", level: Level } | { state: "success" } | { state: "failure", wantsRetry: boolean } | { state: "error", reason: string } (Small excerpt from a game we're developing at $dayjob) You can switch on that and the compiler will know what variant you're talking about, and it will apply exhaustiveness checks (ensures your code will handle all possible states)
- okamiueru 6y agoHaha. That's alright. That looks super neat though, I must admit. The only equivalent that comes to mind would be using an abstract class. I still might fail to fully understand what that code example does, but, would this be somewhat similar? abstract class AppState {} class AppLoading extends AppState { final int progress; } class AppSelectingLevel extends AppState {} class AppPlaying extends AppState { final Level level; } ... Certainly not as neat, but also, not that far off either. Then where you use this app state, you could switch over its `runtimeType`, and in each clause, the IDE will understand which implementation you are dealing with, and actually give you context sensitive help related to that particular state. If you instead only cared about one case, you would be able to do: if (appState is AppPlaying) { doSomething(appState.level); } Would this be somewhat analogous to the functionality you get with unions in typescript?
- kroltan 6y agoIndeed, that is basically what you get from unions, except the exhaustiveness check. Unless I'm mistaken, if one were to later implement a new class that extends AppState, all existing code would compile, but possibly fail or misbehave at runtime, unless you meticulously checked every place that tries to determine something based on those derived types. In TypeScript, adding a new case for an union and not handling it everywhere is a compilation error on every incomplete usage site. For example, try deleting one of the arms of the switch in this playground: https://www.typescriptlang.org/play?ts=4.2.2#code/C4TwDgpgBAMhBuEA2UC8UDeBfKB6XUAIgPYQDOAdgOTBQC2AhsMBAE5QDuAFk1AJa0+ZKADNi7YFyFQIADwZ0wSCADoAUGtCQoAQTBgAysCbRUaqBagAfTFDLGWALigAiJMQYATPhQDmLgBooMFZiX1ZyMmcKAFc6ACM2KCxzSxsMOwcIZxcyZAgAY2AfXwB9ZUQkQOTUi3TMkxylBhAS6orkZzhKmstrW3tG1zIYgoLIl160gayckQY+JBiI6o4GCmAyACUIYFYQZ3jiYmV1qbqZoZc2UNZqiIYyYgpne1YSmrURGIoivmfRMcABSDJy6fRGEwASleew+GFqdg4AgKXCgIKyKlBEChmERfQKj2gbg83j8LmcEWAywoUAABgBxBTQaTuLwlZwAEgwAFkmFwVKEfp4MSYVCEwhEyMIAFRQACMAAZFVCsABSOkAbnxlkJeWG+T+fnKCGQFKgVJprgACqd9XllEUoAwoB0qtq+gSia5mq1yZTdlaXAAJBiIUQ-ACELg9noseuJIzGEwD1NYtJcAE1iDEqBFOD4KGxo5q8AQQXwClCdfHvS55otlhBzZb064GQIoL4Yp4YzWoAnXDdxC3A226QBRVi3LkYbGCiCPZ5YLWIlIpL7AhF9bE5JPjaUuNRYKGaoA https://www.typescriptlang.org/play?ts=4.2.2#code/C4TwDgpgBA... I have to say, the default diagnostic isn't brilliant, but some tooling will give a better error and actually point out the missing arms, instead of complaining about the return type.