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

Support mixins #33

Closed
DartBot opened this issue Oct 10, 2011 · 19 comments
Closed

Support mixins #33

DartBot opened this issue Oct 10, 2011 · 19 comments
Assignees
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). type-enhancement A request for a change that isn't a bug
Milestone

Comments

@DartBot
Copy link

DartBot commented Oct 10, 2011

This issue was originally filed by [email protected]


Traits are interfaces on crack.

Really, it's what interfaces should have been. This would allow developers to code much less.
Traits doesn't have problems of multiple inheritance.

It would be great to have their support in dart. Something like

abstract class Person {
  Schedule schedule()
}
 
trait Student extends Person {
  private var classSchedule = ...
 
  schedule() => classSchedule
 
  learn() => ...
}
 
trait Worker extends Person {
  private var workSchedule = ...
 
  schedule => workSchedule
 
  work() => ...
}
 
class CollegeStudent extends Student with Worker {
  // ...
}

@dgrove
Copy link
Contributor

dgrove commented Oct 11, 2011

Removed Type-Defect label.
Added Type-Enhancement, Area-Language labels.

@DartBot
Copy link
Author

DartBot commented Oct 11, 2011

This comment was originally written by [email protected]


Added Triaged label.

@DartBot
Copy link
Author

DartBot commented Oct 11, 2011

This comment was originally written by [email protected]


The same (here: your example given) could be realized by just inheriting CollegeStudent from Worker...

Basically you are just asking for multiple inheritance at the class level.

@DartBot
Copy link
Author

DartBot commented Oct 12, 2011

This comment was originally written by [email protected]


The given example has an obvious diamond problem (What does CollegeStudent.schedule() return?), and thus appears to just be multiple inheritance in disguise.

My understanding of traits (based on Scala's traits http://www.scala-lang.org/node/126 ) is that they're just interfaces that can contain method bodies. These method bodies can only access the other methods and accessors that the trait declares. When a class is extended with a trait, the defined methods are automatically implemented in that class.

It is technically a subset of multiple inheritance, but much it's easier to think of as an extension of interfaces that can reduce code in situations where every implementing class would have the same definition of one of the interface's methods.

I don't think Dart should have Multiple Inheritance due to the complexity of implementing it in a static compiler, but Traits are quite easy to implement, and provide a lot of the flexibility otherwise desired from Multiple Inheritance.

@gbracha
Copy link
Contributor

gbracha commented Oct 12, 2011

I'm renaming the issue so that its clear what this is about. The confusion between mixins (or their close cousins, traits) and interfaces is not uncommon, but it is confusion nonetheless. Interfaces should not become mixins, but it would be very nice to support mixins in the language. That is something we are considering, but cannot give any commitments on at this time.


Changed the title to: "Support mixins".

@gbracha
Copy link
Contributor

gbracha commented Oct 12, 2011

Set owner to @gbracha.

@DartBot
Copy link
Author

DartBot commented Oct 12, 2011

This comment was originally written by [email protected]


Another option is to just allow to add code in interface but no field.
Cf defender methods in Java

@dgrove
Copy link
Contributor

dgrove commented Feb 3, 2012

Marked this as blocking #1492.

@DartBot
Copy link
Author

DartBot commented Mar 7, 2012

This comment was originally written by [email protected]


+1 also think we need something in this area to be able to succinctly add helpers to existing types. If not traits or mixins than something ala C# methods, or Go langs interface methods.

Either way being able to enhance existing types prevents unnecessary forced abstractions (for devs who inheirt types just to be able to add their own helpers), promote more readable and require less code at the call-site, e.g:

StingUtils.indent(Helper.toCustomFormat(obj));

obj.toCustomFormat().indent();

@DartBot
Copy link
Author

DartBot commented Mar 8, 2012

This comment was originally written by @MarkBennett


Taken from a G+ post I did on this topic... https://plus.google.com/104431949275766772757/posts/BUUeiqhebJC

<rant>

Having had this experience developing large apps in languages with (Ruby, JS, Scala) and without (Java, Python) support for mixins, I am strongly in favour of this feature being added to +Dart : Structured web apps for the following reasons:

First, Interfaces are useful for encouraging well defined interactions between application elements, but they also introduce significant places for code duplication as the interface is implemented in different classes. Define once, write many times makes re-factoring a challenge as the same implementation appears many places throughout the codebase. Mixins address this by providing a shared default implementation which can be extended by classes only when necessary. Defining code in one place reduces the size of the code base and less code to maintain means less potential for unhandled bugs.

Second, mixins can be implemented in such a way that method lookups can all be resolved at compile time preventing any extra lookups during method calls and other performance considerations. This also allows tools to identify potentially conflicting mixin methods. This is not true if implemented using something like Ruby style mixins, but would be true of Scala style traits.

Third, there are well understood ways to consistently resolve method name conflicts between mixins. As long as method resolution is expressly covered in the specification, then tooling can support it and assist developers in understanding which methods will be called when.

Admintedly, there are some rough edges with mixins which can result in some confusion. For example, consider the case where Mixin A and B both implement a #to_s () method. Mixin A and B also both use the #to_s () method in their default implementations expecting a different value to be returned. When these mixins are included in Class X, which #to_s () implementation is used, and which #to_s () method is resolved in the default implementations of Mixin A and B? This situation is theoretical, and my experience in Ruby and JavaScript has taught me that it's not something most developers are likely to experience in real applications, but it is a possibility which will need to be handled by the spec. This is one reason why I firmly believe that any implementation of mixins needs to be able to resolve all Class methods at compile time so developer tools can identify and assist developers in resolving issues like this before code is released.

To wrap-up I really feel that mixins are a valuable part of a modern language, and a tool which can be used to reduce the size and complexity of a code base. They're also a great way to share rich behaviours across a broad range of objects. For example, consider the power of things like the Enumerable mixin in Ruby.

Thanks for reading this post, and taking the time to reflect on the future of web programming. Excited to see how responsive and accessible the Dart team has been making themselves.

</rant>

@DartBot
Copy link
Author

DartBot commented Mar 12, 2012

This comment was originally written by [email protected]


+1 traits/mixins are really missing from the language

@DartBot
Copy link
Author

DartBot commented Apr 22, 2012

This comment was originally written by [email protected]


Traits can be very useful dealing with specialized collections, which have multiple implementations. Say you have a collection Customers, with a method fromCountry(Country c). The implementation is would be something like => _internalList.filter((customer) customer.country == c);

If you have multiple collection classes for Customer, say an Immutable and Mutable variant, or maybe a Set and List, you can simply inherit the trait, and have fromCountry implemented in both. No subclassing, wrapping or a seperate class with static methods is required this way, simplifying code.

@anders-sandholm
Copy link
Contributor

Added apr30-triage label.

@anders-sandholm
Copy link
Contributor

Removed apr30-triage label.

@anders-sandholm
Copy link
Contributor

Added triage1 label.

@DartBot
Copy link
Author

DartBot commented May 1, 2012

This comment was originally written by [email protected]


I originally articulated my thoughts on why we need mixins here: https://github.com/mythz/DartMixins#the-need-for-mixins but I'll re-post my thoughts here in-case the link gets bit-rotted...

Basically the problem is that all core types in Dart (i.e nums, ints, strings, Lists, Maps, etc) are interfaces (which is good) but also means defining additional functionality causes un-due friction since it forces all interface implementors the burden of providing an implementation.

i.e. You have two opposing forces:

  1. To provide useful functionality for built-in types
  2. Not to burden all implementations with maintaining repetitive implementations

If Dart supported Mixins it would allow a single implementation to be shared by all collections.

For an illustrative example let's look at the Collection interface:

Collection extends Iterable
    bool every(predicate)
    Collection filter(predicate)
    void forEach(lambda)
    bool isEmpty()
    int get length()
    Collection map(lambda)
    bool some(predicate)

Out of these only the Iterable interface and length() getter are required since the rest of the API could be added via Mixins, e.g:

Collection c = ..;
void forEach(lambda) => for (var e in c) lambda(e);
bool isEmpty() => c == null || c.length == 0;
...

I don't think the current convention of plurazing the Interface type is a great convention since the core Dart library 'takes' the most obvious name
but provides very little functionality in return, e.g The http://api.dartlang.org/dart_core/Strings.html and http://api.dartlang.org/dart_core/Futures.html classes only have 3 static methods between them, but prevents others from creating static utils with the same name.

@DartBot
Copy link
Author

DartBot commented May 1, 2012

This comment was originally written by @tomaszkubacki


i think c# way is way better with extension methods because no need for new keywords except using already known "this"

e.g adding isEmail method to String type could look like:

bool isEmail(this String s) => { check_if_email_logic_comes_here }

then usage:

String s = "[email protected]"
if(s.isEmail()) {
...
}

Most important reason to add extension methods is that they allow extend core lib types with less common or domain specific functionality.

Also building whole new libs as extension methods is widely used in other languages e.g ServiceStack.OrmLite is a set of high level orm extension methods over low level IDbCommand.
See tutorial at https://github.com/ServiceStack/ServiceStack.OrmLite for more details.

@DartBot
Copy link
Author

DartBot commented May 2, 2012

This comment was originally written by [email protected]


i think c# way is way better with extension methods

FYI, it was already explained a lot of times that C#-style extension methods are a no-go for Dart, because they depend on types. One of Dart's core principles is that type annotations never affect runtime semantics, which is pretty much incompatible with the very idea of extension methods.

@DartBot
Copy link
Author

DartBot commented May 2, 2012

This comment was originally written by @ahmetaa


Not an expert on this issue but there is also Java 8 defender methods to check
http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf

copybara-service bot pushed a commit that referenced this issue May 19, 2022
Changes:
```
> git log --format="%C(auto) %h %s" 7c73ec8..3e695bc
 https://dart.googlesource.com/test_process.git/+/3e695bc Merge pull request #33 from dart-lang/repository_field
 https://dart.googlesource.com/test_process.git/+/da43a51 populate the repository field
 https://dart.googlesource.com/test_process.git/+/18d26e5 Bump actions/checkout from 2 to 3 (#32)
 https://dart.googlesource.com/test_process.git/+/5ec59cb Merge pull request #30 from scheglov/meta-1.3.0
 https://dart.googlesource.com/test_process.git/+/b33c7a2 Revert to 'meta: ^1.3.0'.
 https://dart.googlesource.com/test_process.git/+/4c55feb Merge pull request #29 from scheglov/meta-2.0.0
 https://dart.googlesource.com/test_process.git/+/6b0c025 Update 'meta' constraint to '>=1.3.0 <3.0.0'.
 https://dart.googlesource.com/test_process.git/+/7ac00ea Update test-package.yml (#28)
 https://dart.googlesource.com/test_process.git/+/653e3ba Bump dart-lang/setup-dart from 0.3 to 1 (#27)
 https://dart.googlesource.com/test_process.git/+/d789476 Add dependabot
 https://dart.googlesource.com/test_process.git/+/52732de Merge pull request #26 from dart-lang/franklinyow-patch-1
 https://dart.googlesource.com/test_process.git/+/6c13ab5 Update LICENSE
 https://dart.googlesource.com/test_process.git/+/1c9aadb Fix formatting (#25)
 https://dart.googlesource.com/test_process.git/+/c7416f1 Prepare to publish (#24)

```

Diff: https://dart.googlesource.com/test_process.git/+/7c73ec8a8a6e0e63d0ec27d70c21ca4323fb5e8f~..3e695bcfeab551473ddc288970f345f30e5e1375/
Change-Id: I2bf20858f603f34a3a22bfd19653014035ff4e3c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/245226
Reviewed-by: Kevin Moore <[email protected]>
Commit-Queue: Devon Carew <[email protected]>
This issue was closed.
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). type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

5 participants