IssueRaiser

Users want to define union or union-like APIs

_Based on conversations with @yjbanov, @leonsenft, @mdebbar._ Currently, the Dart language lacks a way to provide static union or union-like semantics or APIs. Multiple other platforms take different approaches - anything from user-definable union types, algebraic/tagged unions, method overloading, and I'm sure other approaches we missed. Let's look at two examples: ## APIs that take nominal types A or B ```dart void writeLogs(Object stringOrListOfString) { if (stringOrListOfString is String) { _writeLog(stringOrListOfString); } else if (stringOrListOfString is List<String>) { stringOrListOfString.forEach(_writeLog); } else { throw ArgumentError.value(stringOrListOfString, 'Not a String or List<String>'); } } ``` ### Problems: * No static type safety. The user can pass an `Octopus`, and only receive an error at runtime: ```dart void main() { // No static error. // Runtime error: "Instance of 'Octopus': Not a String or List<String>". writeLogs(Octopus()); } ``` * Relies on complex TFA for optimizations, which fall apart with dynamic access: ```dart void main() async { // Inferred as "dynamic" for one reason or another. var x = something.foo().bar(); // No static error. Even if it succeeds, all code paths are now retained (disables tree-shaking). writeLogs(x); } ``` ### Solutions * A clever use can simply just write two functions: ```dart void writeLog(String log) { _writeLog(log); } void writeLogList(List<String> logs) { log

Posted by matanlurey on Dec 17, 2018, 11:36 PM

Tags

Related issues

Raise real-world problems, find people facing the same issue, and discuss solutions.4,000 issues0 comments

github (Software)

Users want to define union or union-like APIs

matanlureyDec 17, 2018, 11:36 PM

_Based on conversations with @yjbanov, @leonsenft, @mdebbar._ Currently, the Dart language lacks a way to provide static union or union-like semantics or APIs. Multiple other platforms take different approaches - anything from user-definable union types, algebraic/tagged unions, method overloading, and I'm sure other approaches we missed. Let's look at two examples: ## APIs that take nominal types A or B ```dart void writeLogs(Object stringOrListOfString) { if (stringOrListOfString is String) { _writeLog(stringOrListOfString); } else if (stringOrListOfString is List<String>) { stringOrListOfString.forEach(_writeLog); } else { throw ArgumentError.value(stringOrListOfString, 'Not a String or List<String>'); } } ``` ### Problems: * No static type safety. The user can pass an `Octopus`, and only receive an error at runtime: ```dart void main() { // No static error. // Runtime error: "Instance of 'Octopus': Not a String or List<String>". writeLogs(Octopus()); } ``` * Relies on complex TFA for optimizations, which fall apart with dynamic access: ```dart void main() async { // Inferred as "dynamic" for one reason or another. var x = something.foo().bar(); // No static error. Even if it succeeds, all code paths are now retained (disables tree-shaking). writeLogs(x); } ``` ### Solutions * A clever use can simply just write two functions: ```dart void writeLog(String log) { _writeLog(log); } void writeLogList(List<String> logs) { log

Comments (0)

No comments yet. Start the discussion.

Comment on this issue