-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Scoped object extensions #9991
Comments
BTW, the reason I'm making this request now, is I'm feeling backed into a corner with HTML5 polyfills. The only option I have is to hack on dart:html itself and add @Experimental APIs directly into it. But IMO this is not a viable long term strategy for web platform features. They need time to bake in their own libraries without being forced to ship in Dartium/Chromium. |
Similar to John's dilema, I've been recently asked how you could access properties on an HTML element that were added in JS. This could be the polyfills that John mentions, or application or framework code. Right now the only option seems to be to get a hold of a JS interop Proxy to an element (how might be tricky if elements are automatically converted) and then call methods on that. Extension methods, obviously, could be written to use JS interop but appear to add the method directly to the element. |
Added C1 label. |
fyi scoped objects extensions harmony proposal is dead. |
That's true but I believe that's mostly because the author stopped doing JS-related work and not as much to do with the proposal's merits. |
Scoped Objects Extensions proposal mixes static properties (lexical scope) and dynamic properties (lookup) together which leads to immense implementation complexity. Especially in JavaScript where everything is extremely dynamic and library functions are specified in terms of [[Get]] and [[Put]] that are affected by this in obscure ways. I also think that resulting behavior might be extremely confusing. I honestly think we should not consider adding anything like that to the language. |
This comment was originally written by [email protected] Isn't this request roughly the equivalent of adding a method to an javascript object's prototype at runtime? I believe the resulting functionality is equivalent to C#'s extension methods as well. Given that these are both languages that Dart developers are coming from, I don't see the feature itself as being potentially confusing. Unless there's something I'm missing here...if so, please let me know. I also agree that it provides much needed support for poly filling new browser features, as well as prototyping changes to libraries without affecting the library's entire user base. |
fyi -- for my purposes I don't care if it's scoped or not. Rather the ability to extend an existing type. In essence, parity with JS monkeypatching. |
@vegorov if it is purely dynamic, does that address your concern? look, we can't reject this one hand because it's too static and on another because it's too dynamic. That's just admitting we're stuck in a worst-of-both worlds. We should strive for best-of-both-worlds :) I'm by no means attached to the details of the solution; rather I'm pointing out this is a problem we must solve if we want Dart to be able to make draft web standards available like JavaScript does. Gilad had an interesting idea that requires no language changes: put noSuchMethod on Node, and have a means of delegation. It might work, assuming we can address the dart2js challenges. |
Why not on Object? |
John, What you describe is a very different beast. That goes under the rubric of mirror builders and such. This bug is about a rather ill defined language feature that is a half dynamic cousin of things like C# extension methods, Haskell type classes and others. The literature is littered with such things: Class Boxes, selector namespaces and other variants. |
This comment was originally written by [email protected] I'd like to add that there are mainstream-ish languages doing very similar things: refinements in Ruby 2.0 or augmentations in Golo. |
This comment was originally written by @MarkBennett From a language user perspective, I appreciate the convenience and safety that scoped object extensions add, however after hearing thoughts like these from Charles Nutter of jRuby fame: http://blog.headius.com/2012/11/refining-ruby.html I'm not sure they're worth the complexity it would add to the language unless the rules for handling name collisions were very clear and could all be resolved at compile time. Would a solution implemented with noSuchMethod make compile time checks possible? |
I'm not a Rubyist, so I don't have a solid grasp of Nutter's post, but I believe any scoped-monkey-patch-like proposal for Dart would not suffer from the same problems that refinements have. In particular, he says refinements are available in:
Dart doesn't have any eval forms, much less ones that rebind self, so (3) isn't a problem. I don't think any proposal we'd want for Dart would support (2) either. That gets you back to simpler (i.e. faster) dispatch mechanics. |
This comment was originally written by @MarkBennett Those make sense to me @rnystrom. I honestly don't have any experience with language implementations or VMs so most of my understanding of this issue comes from what I know of Ruby. It would be great to be able to use something like this, especially if it didn't add the VM complexity seen in Ruby. Really happy with how you guys have been trying to integrate as many practical refinements to the language without making the VM or spec to complex. It's a hard balance but you seem to be doing a good job. |
This comment was originally written by [email protected] Yeah, I think that extensions should only be scoped lexically. Heck, I wouldn't even mind to have a special operator for accessing extensions, provided that it's as easy to write and read as a dot. Like colon, for example. |
This comment was originally written by [email protected] Doesnt the problem get solved by allowing inheritance to libraries. For example you // mdv_html.dart // Override function,class,variable definitions // mdv user file |
This comment was originally written by @MarkBennett Not to poke this issue again, but I wanted to share the way Rust is specifying traits, as it's my understanding their successfully able to resolve all method lookups at compile time. Here's the best description of them I was able to find. http://pcwalton.github.io/blog/2012/08/08/a-gentle-introduction-to-traits-in-rust/ As a practical example @wycats is able to expose an implementation of additional methods on an integer using this code: https://github.com/wycats/rust-activesupport/blob/master/dsl.rs You can then call methods like 1.days().ago(). Perhaps the Rust convention of passing self as the first parameter to these functions helps resolve some of the ambiguity in the implementation, and I understand this isn't the Dart norm when defining instance methods on a class or mixin, but could a convention like this be adopted in the case of traits? I only continue to raise this issue as a feature like this would be very useful when prototyping new features that may or may not be accepted into the Dart standard libraries. Thanks again for all the hard work and continuing to have these discussions about the language. Providing a smooth path for prototyping and deprecating language and library features seems like the only element still missing from the Dart ecosystem. |
I realize this is an old topic, but the same thing has been debated in TypeScript with no solution.
_.capitalize is a registered function for the 'this' type, so behaves just like a regular method. More details here: https://www.npmjs.com/package/impulse-js I'm not saying Dart could/should do it that way, but that's how I tackled the problem. It's very straightforward, and as an added bonus, I added partial application if 'this' is undefined:
@munificent I miss Magpie :) |
Sometimes I do too! |
Should the issue description be reworded to take into account the recent developments in the type system as well as include Flutter use-cases? I'd like to have something like this in Flutter too. For example, we have class CommonFinders, which could be made vastly more useful if users could extend it to add domain-specific finders: // package:flutter_test
class CommonFinders {
// ... standard finders ...
}
const CommonFinders find = const CommonFinders._();
// package:flutter_emoji
extend CommonFinders {
Finder emotion(Emotion emotion) => new _EmojiFinder(emotion);
}
// package:chatapp
import 'package:flutter_test';
import 'package:flutter_emoji';
testWidgets('displays happy face', (tester) async {
tester.pumpWidget(new ChatApp());
// Use standard finder
expect(find.text('Chat App'), findsOneWidget);
// Use domain-specific one
expect(find.emotion(Emotion.happy), findsOneWidget);
}); Another example is Flutter's // Today:
build(BuildContext context) {
// Hmm, what can I access via "context"? /goes to docs.flutter.io
// 10 minutes later:
final l10n = MaterialLocalizations.of(context);
final theme = Theme.of(context);
}
// With extensions:
build(BuildContext context) {
// Type "context." + CTRL + Space.
// Gets "localizations", "theme" and other suggestions.
final l10n = context.localizations;
final theme = context.theme;
} To find real-world examples search for ".of(" and "find." in Flutter apps and tests. |
is there any hope on this feature at all? |
There is always hope! Now that Dart has a strong, sound static type system, we have the option of doing statically dispatched extension methods similar to C#, Kotlin, et al. That makes this more feasible than it was before. (The JavaScript "scoped object extensions" proposal never went anywhere, and doing "extension methods" using dynamic dispatch is mostly an unproven research topic at this point. Doing them statically is well-understood.) |
yeah I am also in favor of statically like in kotlin and c# |
Would be great to have! :) |
Is there any hope for this to happen? It would be great for Dart as it is one of my favorite things from Kotlin / C#. It would be a great addition for libs such as |
Most of the discussion is happening in the language repo: dart-lang/language#40 |
I believe we could close this in light of the current language work? Or perhaps I should update the title/description--the goal here was some sort of extension methods; I'm quite happy with the approaches being discussed in the language repository. (Static dispatch seems like the best approach now that we have Dart 2.) |
@jmesserly wrote:
Note that dart-lang/language#177 is a proposal which is designed to be compatible with scoped static extension methods (dart-lang/language#41), such that we can use instance method syntax ( Static extension methods are statically safe in exactly the same way as a global function. The extension methods of dart-lang/language#177 are statically safe in exactly the same way and for exactly the same reasons as a normal instance method. So we don't have to settle for static dispatch only. |
Oh yeah, I saw dart-lang/language#177 and it's really exciting! Closing this one, since we've got other issues tracking the new work. |
In Dart right now, it's painfully difficult to polyfill new features for the HTML nodes without making changes to dart:html itself.
Here's what they do in JavaScript:
https://github.com/toolkitchen/mdv/blob/stable/src/template_element.js
If you include this code into your application, it seamlessly extends a bunch of DOM types, giving you access to new features. It can do this without requiring you to download a new browser or rebuild Chrome yourself.
I don't see how we can do this in Dart. You can't add an instance method to dart:html types without changing the code of dart:html itself. This shuts down a valuable source of prototyping and feedback for the DOM APIs.
JavaScript has a proposal for "scoped object extensions" that is friendly to dynamic typing:
http://wiki.ecmascript.org/doku.php?id=strawman:scoped_object_extensions
The problem for JS is they don't have much urgency. They get by okay with monkeypatching existing types (see my example above). In Dart we don't have monkeypatching, so we need something else.
Note: IMO, this should not be merged into issue #13, because that bug was closed because it asked for statically typed extension methods. Here I want to discuss the above proposal that relies on dynamic typing. At least, if this one is to be WontFix'd, it should be done for a different reason :)
The text was updated successfully, but these errors were encountered: