Skip to content

Commit 95336f1

Browse files
authored
Proposal for #107 - implicit constructors (#105)
1 parent 15a5db7 commit 95336f1

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Implicit Constructors
2+
3+
4+
5+
## Motivation
6+
7+
Every place in `pkg:http` with a `url` parameter types it as `dynamic`.
8+
9+
```dart
10+
Future<Response> get(url, {Map<String, String> headers}) => ...
11+
12+
void doWork() async {
13+
await get('http://example.com');
14+
await get(Uri.parse('http://example.com'));
15+
await get(42); // statically fine, but causes a runtime error
16+
}
17+
```
18+
19+
This is to support a common use case: devs often want to pass either `Uri`
20+
*or* `String` to such methods. In the end, all `String` values are "upgraded"
21+
to `Uri` before use. To support the desired flexibility, the user risks
22+
runtime errors if something other than `String` or `Uri` are provided.
23+
24+
Flutter avoids this issue, by being explicit about types everywhere.
25+
26+
```dart
27+
// Flutter
28+
void giveMeABorder(BorderRadiusGeometry value) {}
29+
30+
void doWork() {
31+
giveMeABorder(const BorderRadius.all(
32+
Radius.circular(18),
33+
));
34+
35+
// User would like to write this, but...
36+
giveMeABorder(18); // static error
37+
}
38+
```
39+
40+
The existing request(s) for union types –
41+
https://github.com/dart-lang/sdk/issues/4938 and
42+
https://github.com/dart-lang/language/issues/83
43+
– could be an option here, but it would require updating all parameters
44+
and setters to specify the supported types.
45+
46+
An alternative: implicit constructors.
47+
48+
## Syntax
49+
50+
*This is all PM spit-balling at the moment...*
51+
52+
* Introduce a new keyword – `implicit` – that can be applied to a constructor or
53+
factory.
54+
55+
```dart
56+
class Uri {
57+
// Note: parse is currently a static function on Uri, not a constructor.
58+
implicit Uri.parse(String uri) => ...
59+
}
60+
61+
class BorderRadiusGeometry {
62+
implicit factory BorderRadiusGeometry.fromDouble(double radius) =>
63+
BorderRadius.all(Radius.circular(18));
64+
}
65+
66+
class Widget {
67+
implicit factory Widget.fromString(String text) => Text(text);
68+
}
69+
70+
// NOTE - for both Widget and BorderRadiusGeometry, you really want a
71+
// `const implicit factory`. Supporting `const factory` seems like a necessary
72+
// precursor.
73+
```
74+
75+
* When evaluating an assignment to type `T`, if the provided value `P` is
76+
not of type `T`, then look for an implicit constructor/factory on `T` that
77+
supports an instance of `P`. If it exists, use it.
78+
79+
## Other implementations
80+
81+
* C# - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/implicit
82+
* Scala - https://docs.scala-lang.org/tour/implicit-conversions.html
83+
* Leaf has warned about Scala's support for cascading implicit conversions
84+
(e.g. int -> Duration -> Time). Dart should avoid this!

0 commit comments

Comments
 (0)