Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typedef for simple type aliases #2626

Closed
rakudrama opened this issue Apr 18, 2012 · 47 comments
Closed

typedef for simple type aliases #2626

rakudrama opened this issue Apr 18, 2012 · 47 comments
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). core-a type-enhancement A request for a change that isn't a bug

Comments

@rakudrama
Copy link
Member

rakudrama commented Apr 18, 2012

In the dom library there are several types which are sum (union) types.

IDBKey and SerializedScriptValue are two examples - both include numbers, strings and JavaScript arrays (Lists) among other things, and neither includes functions or arbitrary user defined types.

We are forced to use Dynamic for these types.
If typedef could do a simple renaming we could generate more readable interfaces.

e.g.

interface IDBFactory {
   int cmp(Dynamic first, Dynamic second);
}

could become

/** Documentation about IDBKey in one place. */
typedef IDBKey = Dynamic;

interface IDBFactory {
   int cmp(IDBKey first, IDBKey second);   // Tools can navigate to the definition.
}
@gbracha
Copy link
Contributor

gbracha commented Apr 18, 2012

Clearly typedefs should allow type aliasing for all types. I hope we can fix this soon.


Set owner to @gbracha.
Added Accepted label.

@gbracha
Copy link
Contributor

gbracha commented Apr 18, 2012

See also bug 84.

@gbracha
Copy link
Contributor

gbracha commented May 24, 2012

Added this to the Later milestone.

@rakudrama
Copy link
Member Author

See Issue #6292 for another example.
Lack of simple typedef continues to be an impediment.


cc @larsbak.

@DartBot
Copy link

DartBot commented May 4, 2013

This comment was originally written by george.moscho...@gmail.com


Any ETA wrt type aliasing for all types? Will this make 1.0?

@kasperl
Copy link

kasperl commented Jul 10, 2014

Removed this from the Later milestone.
Added Oldschool-Milestone-Later label.

@kasperl
Copy link

kasperl commented Aug 4, 2014

Removed Oldschool-Milestone-Later label.

@rakudrama rakudrama added Type-Enhancement area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). labels Aug 4, 2014
@rkj
Copy link

rkj commented Oct 29, 2015

Any updates? Will it be ever possible? We have some long classes names that are really awkward to use (to the point where it's impossible to fit the case statement on single line), and aliasing them to an abbreviation would greatly help.

@korsvanloon
Copy link

I could really use typedefs for aliasing my long generic classes like so:

class Something<A,B,C,D,E> { }

typedef Something<Foo, Bar, Baz, Qux, Quux> SomethingFoo;

@RSSchermer
Copy link

Also perhaps for future consideration: if the Dart team/committee ever decides to add union types to the language (#4938) I think arbitrary type aliasing would be very useful for dealing with the unwieldy types this might produce.

My current use case concerns vertex attribute types (for WebGL rendering). If Dart were to allow something like this I'd be a very happy Dartisan:

typedef VertexAttribute = double | Vector2 | Vector3 | Vector4 | Matrix2 | Matrix3 | Matrix4;

@eernstg
Copy link
Member

eernstg commented Feb 16, 2016

Thanks for the input! I'm on the Dart team, and I think we'll have union types and maybe the generalized typedefs as well (and I also want them), but it's always a much more involved process to change the language than you'd think. Even though I can't promise you that they will be added anytime soon, your input helps keeping the priority of these features in place.

@kevmoo kevmoo added P2 A bug or feature request we're likely to work on type-enhancement A request for a change that isn't a bug and removed accepted labels Feb 29, 2016
@tmst
Copy link

tmst commented Oct 22, 2016

Just wondering, would this enhancement allow the following construct?

class Foo {}

void main() {
var FooClass = Foo;
foo = new FooClass();
}

@eernstg
Copy link
Member

eernstg commented Oct 24, 2016

No, being able to access constructors via a value of type Type is a reflective operation ('dart:mirrors' and package reflectable will allow you to do such a thing via reflectType and ClassMirror.newInstance), and the feature discussed in this issue does not provide a way to allow a typedef to provide similar functionality. However, depending on the context, you might be able to pass around a factory function rather than the Type itself, and the factory function could carry some type information:

class Foo {}
class Foo2 extends Foo {}

typedef Foo FooFactory();

void main() {
  FooFactory myFooFactory = () => new Foo2();
  Foo foo = myFooFactory();
}

@eseidelGoogle
Copy link

I suspect the importance of this bug is going to rise with strong_mode (@leafpetersen) since longer types are going to be more common, and folks are going to want to shorten them (as per the ask in #2626 (comment)).

@eseidelGoogle
Copy link

I'm told that #27527 is viewed as a precursor to this more general issue and is under evaluation currently.

@aemino
Copy link

aemino commented Aug 30, 2017

Is this still being considered? Personally, I view union types and typedefs that are used for more than just functions to be almost imperative to Dart. I find myself in so many situations where dynamic could be used, but union typedefs would be a more concrete and specific way to define a type.

@leafpetersen
Copy link
Member

This is not planned for Dart 2.0. It is still on the list of things that we would like to consider for future releases.

@lrhn lrhn removed the P2 A bug or feature request we're likely to work on label Dec 6, 2018
@stt106
Copy link

stt106 commented Dec 9, 2018

Just to add, adding type alias is going to make dart compile time even safer, just because two values of the same type doesn't mean they should be compared or assigned to each other. This is one of the primary reasons why many languages like Go, F# allow type alias. A naive example would be a function that does conversion between Celsius and Fahrenheit. Naturally people want to define both of them as double but then it's very easy to unintentionally mix up the two since they're both just doubles.

If allowing type alias, one can easily do
type Celsius double // or a similar syntax
type Fahrenheit double
Fahrenheit CToF(Cesius c) => Fahrenheit(c*9/5 + 32);

@lrhn lrhn added this to Non-Breaking And Simple in Language Enhancement Categories Dec 14, 2018
@zhengxiaoyao0716
Copy link
Contributor

zhengxiaoyao0716 commented Feb 16, 2019

Maybe we don't need to use type or typedef for type alias?
In my opinion, since Dart support the syntax like class =, it is a better way to implements type alias.

For the example that @stt106 gived, maybe we can use class = to implements it like this:

class Celsius = double;
class Fahrenheit = double;
Fahrenheit cToF(Celsius c) => Fahrenheit((c as double) * 9 / 5 + 32);

I thinks that the above syntax is easier to understand in Dart, because of we can simply simulate it now!
Here my "polyfill":

import 'package:test_api/test_api.dart';

class Celsius = Alias<double> with Type;
class Fahrenheit = Alias<double> with Type;
Fahrenheit cToF(Celsius c) => Fahrenheit(c.as(double) * 9 / 5 + 32);

class Alias<T> {
  final T _value;

  const Alias(T value) : _value = value;
  Alias.of(Alias<T> other) : this(other._value);

  T /*operator*/ as(Type type) {
    if (type == _value.runtimeType) return _value;
    throw _CastError(runtimeType, type);
  }

  @override
  String toString() {
    return _value.toString();
  }

  @override
  bool operator ==(other) =>
      other.runtimeType == this.runtimeType && other._value == _value;
  @override
  int get hashCode => _value.hashCode;
}

class _CastError extends CastError {
  final Object message;
  _CastError(Type alias, Type expected)
      : message = "alias '$alias' is not type '$expected' in type cast";
  @override
  String toString() => message;
}

void main() {
  test('playground', () async {
    var celsius = Celsius(30.0);
    print('Celsius: $celsius');

    var fahrenheit = cToF(celsius);
    print('Fahrenheit: $fahrenheit');

    expect(fahrenheit.as(double), 86.0);
  });
}

@rrousselGit
Copy link

rrousselGit commented Feb 16, 2019

I disagree.

class Foo = Bar with Mixin syntax is used to create a new type. Such that Foo != Bar

But i think that a class Foo = Bar can be interesting.

This especially matters when we take the extension methods proposal in consideration.

@eernstg
Copy link
Member

eernstg commented Feb 18, 2019

This is now happening. As of 02bb437 (Jan 11, 2019) it is part of the language specification that you can write type aliases like typedef C = D<int>; and typedef D<X extends num> = Map<X, List<X>>;, etc.

There's an implementation plan. Right now some other things are being pushed harder than this feature, but it's accepted and in the pipeline.

Note that you can not use this feature to create new types (similar to Haskell's newtype or Pascal's type Temperature = Integer;), it creates an additional notation for an existing type. So if you declare typedef D = C; then it is type correct to have things like D d = C();.

It is for abbreviation and consistency, not for "branding" of types (that is, creating a "copy" of a type that has the same underlying properties and representation, but which is considered during type checking to be a different type). Type aliases wouldn't fit very well for type branding, anyway, because they have always been specified to create a new way to write an existing type rather than creating a new type.

We did have some discussions about type branding (e.g., I wrote dart-lang/linter#1264 at some point in response to such discussions), but that discussion should be taken separately.

So I think we can close this issue now (before it turns 7 ;-). @rakudrama, do you agree?

@atreeon
Copy link

atreeon commented Feb 20, 2019

Is this functionality in a version of dart in which we can use? I'm using 2.2.0-dev.1.1
'Error: Can't create typedef from non-function type.'
typedef X = List<int>;

@eernstg
Copy link
Member

eernstg commented Feb 20, 2019

It is not yet implemented, and it won't make it into Dart 2.2, but it is coming. Also, there is no bleeding-edge version of the tools that have it yet, so you have to find a tiny extra bit of patience somewhere. ;-)

I suggested closing this issue because it's about the language—the implementation process would be associated with the implementation plan and its associated issues.

@atreeon
Copy link

atreeon commented Feb 20, 2019

ok thanks, I'll keep an eye on the changelog in future! (I'm terrible during the buildup to christmas too ;-) The feature looks great!
btw, will you be able to alias just a simple type like int. I thought this might help with documenting return types from functions
typedef userId = int;

@eernstg
Copy link
Member

eernstg commented Feb 21, 2019

@twistedinferno wrote:

will you be able to alias just a simple type like int. I thought this might
help with documenting return types

A type alias like typedef userId = int; is certainly possible with this feature. I guess there will be a need to develop good software engineering practices around such things in order to ensure that it is actually helpful, but that's of course true for many language features.

@rayfarias56
Copy link

rayfarias56 commented Jun 26, 2019

So I believe this issue recently turned 7. Is there any update on the implementation progress? It seemed that this was so close to being implemented about 4 months ago.

@eernstg
Copy link
Member

eernstg commented Jun 27, 2019

Right, it's still very close. ;-)

There is some work on it too, e.g., here's a test: https://github.com/dart-lang/co19/blob/master/Language/Types/Type_Aliases/syntax_t02.dart.

Sorry about the delay, but other features (e.g., NNBD) have a very high priority, and this one is in the pipeline now.

@DanielBiegler
Copy link

Just found this issue since I also was looking for this feature. I see the last commit from here is over 3 months old.

But I still see some issues about NNBDs, so I guess it might take some time still. Is there something new that could be said about this? 😄 Cheers!

@eernstg
Copy link
Member

eernstg commented Sep 9, 2019

Yes, NNBD and static extension methods are taking up the resources now. So, unfortunately, we're close, but we aren't actively getting any closer at this point. Thanks for pushing the issue, however: The only way to get it into the implementation pipeline is that there is a perceived need.

@giovanni-orciuolo
Copy link

I need this. I wonder why it wasn't included in the language from the start... I often use type aliases to simplify complicated variable types while still maintaining 100% safety! It's a practice that carried over from C++

@antekone
Copy link

Any chances of implementing this feature?

@leafpetersen
Copy link
Member

This is still planned to be implemented, but it's lower on the priority list right now. There's a strong feeling on the team that we need to focus on landing any breaking features (like NNBD) now, since they will just get harder to land as time goes on, and also a desire to prioritize the higher impact features (like extension methods) above smaller features. We still think this is a great feature and look forward to landing it when we can find a good slot for it!

@GAM3RG33K
Copy link

is this feature still in the development pipeline? I need this really bad. I want to use it to map 'Map<String, dynamic>' to 'JsonObject'.

@giovanni-orciuolo
Copy link

is this feature still in the development pipeline? I need this really bad. I want to use it to map 'Map<String, dynamic>' to 'JsonObject'.

Tbh they should just give us an alias like that built-in. In my projects I mainly use Map<String, dynamic> for JSON objects, rarely for other stuff

@mindplay-dk
Copy link

mindplay-dk commented Nov 10, 2019

Just wondering, is it really a good idea to overload the typedef keyword with a different feature?

EDIT: it's probably fine, see notes below.

As far as my understanding, type aliases are quite a different thing from type definitions - since a type-definition declares a new type, whereas a type alias merely declares an alias for an existing type, right?

So if typedef worked consistently with the function types you can declare today, which are new types, I would expect e.g. typedef UserId = int to also generate a new type, e.g. UserId would be assignable to int, but int would not be assignable to UserId without an explicit type-cast or assertion of some sort. (This is useful for things like IDs which aren't just any numbers, or e.g. typedef HexColorCode = string, which is a string that requires a validating constructor, so you can statically guarantee that a HexColorCode is not just any string, but a string with a specific length and format.)

As opposed to type aliases, which type-check more like interfaces - e.g. in TypeScript, a declaration such as type HexColorCode = string doesn't declare a new type, but just an alias for an existing type. So a HexColorCode is assignable to a string, and vice-versa. (This has it's own set of use-cases - often just to avoid repeating the same complex type-expression over and over, which can make a codebase more difficult to refactor.)

I think both of these features are useful - but if these new typedef = declarations are just for declaring type aliases, I would suggest introducing a dedicated keyword like type for that, to avoid any confusion about a given typedef generating a new type or just a type alias. This would also make it possible to overload typedef in the future with a similar feature that does generate unique types.

Thoughts?

@GAM3RG33K
Copy link

GAM3RG33K commented Nov 10, 2019

Just wondering, is it really a good idea to overload the typedef keyword with a different feature?

As far as my understanding, type aliases are quite a different thing from type definitions - since a type-definition declares a new type, whereas a type alias merely declares an alias for an existing type, right?

So if typedef worked consistently with the function types you can declare today, which are new types, I would expect e.g. typedef UserId = int to also generate a new type, e.g. UserId would be assignable to int, but int would not be assignable to UserId without an explicit type-cast or assertion of some sort. (This is useful for things like IDs which aren't just any numbers, or e.g. typedef HexColorCode = string, which is a string that requires a validating constructor, so you can statically guarantee that a HexColorCode is not just any string, but a string with a specific length and format.)

As opposed to type aliases, which type-check more like interfaces - e.g. in TypeScript, a declaration such as type HexColorCode = string doesn't declare a new type, but just an alias for an existing type. So a HexColorCode is assignable to a string, and vice-versa. (This has it's own set of use-cases - often just to avoid repeating the same complex type-expression over and over, which can make a codebase more difficult to refactor.)

I think both of these features are useful - but if these new typedef = declarations are just for declaring type aliases, I would suggest introducing a dedicated keyword like type for that, to avoid any confusion about a given typedef generating a new type or just a type alias. This would also make it possible to overload typedef in the future with a similar feature that does generate unique types.

Thoughts?

I would prefer a separate keyword for declaring alias.
Maybe define or declare can be used for it.

for ex.
define JSON as Map<String, dynamic>

So that after this I can use JSON.containsKey()

@eernstg
Copy link
Member

eernstg commented Nov 11, 2019

A type alias (that is, a declaration starting with typedef) declares an alias for an existing type, and that will also be the case for the generalized type aliases. In particular, if e is an expression of type T and TAlias is an alias for the type T, TAlias x = e; is allowed. The only difference is that a type alias will currently only create an alias for a function type, and the generalized kind will allow for creating an alias for any type.

@mindplay-dk
Copy link

@eernstg oh, so I have this backwards? The typedef keyword in Dart doesn't define new types - they're only aliases, like the type keyword in TypeScript?

In that case, the proposal is consistent with existing behavior, and my whole argument is moot, so please feel free to mark it as irrelevant to save other readers some time! 😊

@eernstg
Copy link
Member

eernstg commented Nov 11, 2019

That's correct: A typedef in Dart does not define a new type, just a new syntax to denote an existing one.

It does come up, and we do recognize that the ability to define a new type associated with an existing representation is a useful tool (e.g., in order to enforce that a given representation is only used in ways that are suitable for a given interpretation of that representation, e.g., such that we don't add a weight and and height which are both represented as a double). But that's a different topic.

PS: In case I change my mind about a comment on an issue I usually go back and edit it, with an [Edit: <some-explanation>] at the top in case it isn't a mere typo fix. 😄

@mit-mit
Copy link
Member

mit-mit commented Nov 20, 2019

Closing this as we're now tracking this in dart-lang/language#65

@mit-mit mit-mit closed this as completed Nov 20, 2019
dart-bot pushed a commit that referenced this issue Oct 14, 2020
git log --oneline cf9795f3bb209504c349e20501f0b4b8ae31530c..f0c7771b38155d3829a60d60b5dba2784b100811
f0c7771b Set first version with null safety to 2.12 (#2684)
df1140af Warn from get, when mixed mode (#2590)
765778c0 Simplify test detection (#2682)
afd66ea2 Inline the single test asset. (#2681)
059e4796 Simplify the logic for unicode and colors in output (#2679)
35ddaec2 Dartify test tool (#2680)
62f26401 Example for User-Agent (#2678)
e8b4b114 fixes: #2670 pub global activate commands always exit cmd on windows. (#2671)
93e703b1 Improve stack traces in many tests (#2673)
5b540a39 Fix experiments tests for Dart 2.11 (#2672)
b0ac77d8 Bump dependency on pkg:analyzer (#2662)
73f0906e Removed @alwaysThrows (#2642)
88e0a83c Fixed bug in adding dependency to empty dependencies key (#2640)
135d9fa0 Pub add/remove now remove dependencies key if it makes them empty (#2639)
f4cc9673 Fix "pubpsec" typo (#2641)
4686d74d Adding an existing package is now a dataError (#2638)
1e93f47c Checks pubspec keys for potential typos (#2616)
fa5f51ef Vendor yaml_edit (#2633)
ac6d307f Adding a `pub remove` command (#2620)
9d236e00 Adding the `pub add` command (#2618)
04e237f7 Drop upper bound instead of using "any" while resolving in "pub outdated" (#2623)
93954f33 Use InternetAddress.tryParse over try/catch (#2626)
638c81c9 Refine publishing message (#2624)


Allow github


Embed pub as a library into dartdev

Change-Id: Iadc6acb5c3425dfb8848db89820e6c9c8caf16ba
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/167574
Reviewed-by: Jonas Jensen <jonasfj@google.com>
Commit-Queue: Sigurd Meldgaard <sigurdm@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). core-a type-enhancement A request for a change that isn't a bug
Projects
Language Enhancement Categories
Non-Breaking And Simple
Development

No branches or pull requests