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

Comments

Projects
None yet
5 participants
@DartBot
Copy link

commented Oct 10, 2011

This issue was originally filed by paulpmill...@gmail.com


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

This comment has been minimized.

Copy link
Member

commented Oct 11, 2011

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

@DartBot

This comment has been minimized.

Copy link
Author

commented Oct 11, 2011

This comment was originally written by drfibonacci@google.com


Added Triaged label.

@DartBot

This comment has been minimized.

Copy link
Author

commented Oct 11, 2011

This comment was originally written by carstenkl...@yahoo.de


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

This comment has been minimized.

Copy link
Author

commented Oct 12, 2011

This comment was originally written by binary...@binarysplit.com


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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Contributor

commented Oct 12, 2011

Set owner to @gbracha.

@DartBot

This comment has been minimized.

Copy link
Author

commented Oct 12, 2011

This comment was originally written by remi....@gmail.com


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

@dgrove

This comment has been minimized.

Copy link
Member

commented Feb 3, 2012

Marked this as blocking #1492.

@DartBot

This comment has been minimized.

Copy link
Author

commented Mar 7, 2012

This comment was originally written by demis.bellot...@gmail.com


+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

This comment has been minimized.

Copy link
Author

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

This comment has been minimized.

Copy link
Author

commented Mar 12, 2012

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


+1 traits/mixins are really missing from the language

@DartBot

This comment has been minimized.

Copy link
Author

commented Apr 22, 2012

This comment was originally written by rtimo...@gmail.com


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

This comment has been minimized.

Copy link
Contributor

commented Apr 30, 2012

Added apr30-triage label.

@anders-sandholm

This comment has been minimized.

Copy link
Contributor

commented May 1, 2012

Removed apr30-triage label.

@anders-sandholm

This comment has been minimized.

Copy link
Contributor

commented May 1, 2012

Added triage1 label.

@DartBot

This comment has been minimized.

Copy link
Author

commented May 1, 2012

This comment was originally written by demis.bellot...@gmail.com


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

This comment has been minimized.

Copy link
Author

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 = "someone@google.com"
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

This comment has been minimized.

Copy link
Author

commented May 2, 2012

This comment was originally written by ladicek@gmail.com


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

This comment has been minimized.

Copy link
Author

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

@cgiess cgiess referenced this issue Jan 18, 2019

Closed

dart2js crash #35697

dart-bot pushed a commit that referenced this issue Feb 11, 2019

Give more context when initializing from dill fails
Previously, if failing when trying to load from a dill it would say
something like

Warning: Tried to initialize from a previous compilation
(build/app.dill), but couldn't. Error message was
'NoSuchMethodError: The method 'getReference' was called on null.
Receiver: null
Tried calling: getReference()'. This might be a bug.
The Dart team would greatly appreciate if you would take a moment to
report this problem at http://dartbug.com/new.

Which really doesn't give us a lot to go on.

This CL changes that to also give us a little go to on, and report
something like

Warning: Tried to initialize from a previous compilation
(org-dartlang-test:///initializeFrom.dill), but couldn't.
Error message was 'NoSuchMethodError: The method 'getReference' was
called on null.
Receiver: null
Tried calling: getReference()'. Stacktrace included '#0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
#1      BinaryBuilder.readLibraryReference (package:kernel/binary/ast_from_binary.dart:692:9)
#2      BinaryBuilder.readLibraryDependency (package:kernel/binary/ast_from_binary.dart:837:25)
#3      BinaryBuilder._readLibraryDependencies (package:kernel/binary/ast_from_binary.dart:829:33)
#4      BinaryBuilder.readLibrary (package:kernel/binary/ast_from_binary.dart:803:5)
#5      BinaryBuilder._readOneComponent (package:kernel/binary/ast_from_binary.dart:634:7)
#6      BinaryBuilder.readComponent (package:kernel/binary/ast_from_binary.dart:441:7)
#7      IncrementalCompiler.initializeFromDill (package:front_end/src/fasta/incremental_compiler.dart:395:14)
<asynchronous suspension>
#8      IncrementalCompiler.computeDelta.<anonymous closure> (package:front_end/src/fasta/incremental_compiler.dart:126:23)
<asynchronous suspension>
#9      CompilerContext.runInContext.<anonymous closure>.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:120:46)
#10     new Future.sync (dart:async/future.dart:224:31)
#11     CompilerContext.runInContext.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:120:19)
#12     _rootRun (dart:async/zone.dart:1124:13)
#13     _CustomZone.run (dart:async/zone.dart:1021:19)
#14     _runZoned (dart:async/zone.dart:1516:10)
#15     runZoned (dart:async/zone.dart:1463:12)
#16     CompilerContext.runInContext (package:front_end/src/fasta/compiler_context.dart:119:12)
#17     IncrementalCompiler.computeDelta (package:front_end/src/fasta/incremental_compiler.dart:108:20)
<asynchronous suspension>
#18     initializedCompile (file:///usr/local/google/home/jensj/code/dart-sdk/sdk/pkg/front_end/test/incremental_load_from_dill_test.dart:397:51)
<asynchronous suspension>
#19     basicTest (file:///usr/local/google/home/jensj/code/dart-sdk/sdk/pkg/front_end/test/incremental_load_from_dill_test.dart:167:34)
<asynchronous suspension>
#20     RunCompilations.run (file:///usr/local/google/home/jensj/code/dart-sdk/sdk/pkg/front_end/test/incremental_load_from_dill_test.dart:101:15)
<asynchronous suspension>
#21     ChainContext.run.doStep.<anonymous closure> (package:testing/src/chain.dart:180:33)
<asynchronous suspension>
#22     new Future.<anonymous closure> (dart:async/future.dart:176:37)
#23     _rootRun (dart:async/zone.dart:1120:38)
#24     _CustomZone.run (dart:async/zone.dart:1021:19)
#25     _CustomZone.runGuarded (dart:async/zone.dart:923:7)
#26     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
#27     _rootRun (dart:async/zone.dart:1124:13)
#28     _CustomZone.run (dart:async/zone.dart:1021:19)
#29     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:947:23)
#30     Timer._createTimer.<anonymous closure> (dart:async/runtime/libtimer_patch.dart:21:15)
#31     _Timer._runTimers (dart:isolate/runtime/libtimer_impl.dart:382:19)
#32     _Timer._handleMessage (dart:isolate/runtime/libtimer_impl.dart:416:5)
#33     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
'. This might be a bug. The Dart team would greatly appreciate if you would take a moment to report this problem at http://dartbug.com/new.

which will hopefully allow us to actually debug any such reports.

Change-Id: I13bdd4f96c1e4bb2dcce91e533442b48c87c9e0c
Reviewed-on: https://dart-review.googlesource.com/c/85348
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>

This issue was closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.