Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

scoped object extensions #9991

Open
jmesserly opened this Issue · 19 comments

7 participants

@jmesserly
Collaborator

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 :)

@jmesserly
Collaborator

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.

@justinfagnani
Collaborator

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.

@gbracha
Collaborator

Needs study.


Set owner to @gbracha.
Added Accepted label.

@dgrove
Owner

Added C1 label.

@mraleph
Collaborator

fyi scoped objects extensions harmony proposal is dead.

@munificent
Collaborator

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.

@mraleph
Collaborator

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.

@DartBot
Collaborator

This comment was originally written by Jim.J....@gmail.com


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.

@jmesserly
Collaborator

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.

@jmesserly
Collaborator

@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.

@munificent
Collaborator

Gilad had an interesting idea that requires no language changes: put noSuchMethod on Node, and have a means of delegation.

Why not on Object?

@gbracha
Collaborator

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.

@DartBot
Collaborator

This comment was originally written by ladicek@gmail.com


I'd like to add that there are mainstream-ish languages doing very similar things: refinements in Ruby 2.0 or augmentations in Golo.

@DartBot
Collaborator

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?

@munificent
Collaborator

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:

  1. The direct scope, such as the top-level of a script, the body of a class, or the body of a method or block
  2. Classes down-hierarchy from a refined class or module body
  3. Bodies of code run via eval forms that change the "self" of the code, such as module_eval

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.

@DartBot
Collaborator

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.

@DartBot
Collaborator

This comment was originally written by ladicek@gmail.com


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.

@DartBot
Collaborator

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


Doesnt the problem get solved by allowing inheritance to libraries. For example you
can have a mdv_html library which inherits code from html but overrides some methods and adds a few more

// mdv_html.dart
library mdv_html extends dart:html;

// Override function,class,variable definitions

// mdv user file
import "package:mdv_html"

@DartBot
Collaborator

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.

@gbracha gbracha was assigned by jmesserly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.