jupyter-widgets / ipywidgets

Interactive Widgets for the Jupyter Notebook
https://ipywidgets.readthedocs.io
BSD 3-Clause "New" or "Revised" License
3.16k stars 950 forks source link

Typescript #14

Closed jdfreder closed 8 years ago

jdfreder commented 9 years ago

Should we convert the widgets to Typescript? Or instead to ES6?

My feeling is that as long as we can maintain easy (unchanged) access to our Javascript users, we should give Typescript a shot.

Adding to next week's dev meeting.

jasongrout commented 9 years ago

+1 to typescript

jdfreder commented 9 years ago

More thoughts, I've done this type of migration before. I think we should initially move to ES6 and then consider moving to Typescript (breaking it into two steps is easier). Leaving open as 5.0.

bollwyvl commented 8 years ago

I was just doing a bit of refactoring of some older widgets into ES6, and hit the Backbone and ES6 Classes issue. Follow-up here with workarounds. Basically, static properties are not really supported, and backbone uses them all over, events, etc. and we've added a few serializers. There are a few uses, such as events in ButtonView, but the more troubling serializers in WidgetModel (which has given me some trouble) might be a showstopper, as almost anybody that does custom work is going to have to monkey with this. One solution would be make sure we can accept functions for any custom properties (right now, serializers must be an POJO), which would clean up the inheritance story.

TypeScript supports static properties, but they end up as Class.someProperty, and not this.someProperty, which probably won't work.

Since there will be a relatively narrow time when one WON'T need a transpiler, going straight to ES7, which supports decorators, might be attractive. In the follow-up, that example really does read nicely in comparison to the others.

In the near term, I'm going to make do with one of the workarounds (when I pick one) but this may be a thing to watch out for when picking a direction!

jdfreder commented 8 years ago

Yeah I read about that problem regarding backbone recently. I'm glad that you're heading the investigation on this @bollwyvl , and am curious to see what method you choose. Please ping me. Thanks! :)

bollwyvl commented 8 years ago

I'm leaning towards the es7 decorator approach. Used appropriately, i think they offer a really nice visual way to inject just enough code, a la flask. Used badly, well: http://blog.jooq.org/2015/04/15/how-jpa-2-1-has-become-the-new-ejb-2-0/

However, in the case of serializers, i think we should accept/expect a static method, as they nearly always need inheritance, albeit by _.extend today. Using super will make it more clear... That might come as a pr, along with some forensics on the changes since last i really dug into the widgets source... I've been in consumer mode for a while.

Of course, typescript will (soon?) support decorators, so the es7 route could be fruitful. But none of my stuff is typeful yet, so that would constitute even more scale up for me, but is, as you said, the right long term direction.

Will update/link when I've got something going!

On 17:46, Fri, Nov 20, 2015 Jonathan Frederic notifications@github.com wrote:

Yeah I read about that problem regarding backbone recently. I'm glad that you're heading the investigation on this @bollwyvl https://github.com/bollwyvl , and am curious to see what method you choose. Please ping me. Thanks! :)

— Reply to this email directly or view it on GitHub https://github.com/ipython/ipywidgets/issues/14#issuecomment-158547790.

jdfreder commented 8 years ago

But none of my stuff is typeful yet, so that would constitute even more scale up for me, but is, as you said, the right long term direction.

Will update/link when I've got something going!

I'm more interested in the transition from ES5->ES6 because it and modern Javascript browser APIs will dramatically simplify ipywidgets. I have that transition targeted for 6.0 (master === 5.0dev). The addition of types to the codebase, if we agree to do that, will be a separate step, for 7.0 or later. So you won't have to worry about that yet. :)

Of course, typescript will (soon?) support decorators, so the es7 route could be fruitful.

I thought it did now? Doesn't it just implement them not to spec, or a way that disagrees with babel?

bollwyvl commented 8 years ago

I thought it did now? Doesn't it just implement them not to spec, or a way that disagrees with babel?

I'm just not up to speed on what is in and out... they have been releasing stuff at quite a clip, and I'm not using it yet. Research ensues!

ellisonbg commented 8 years ago

The decorator spec hasn't been finalized and the Babel and TypeScript implementations are incompatible. I am -1 on using decorators until the spec is final and all transpilers are doing the same thing.

On Fri, Nov 20, 2015 at 3:12 PM, Nicholas Bollweg notifications@github.com wrote:

I'm leaning towards the es7 decorator approach. Used appropriately, i think they offer a really nice visual way to inject just enough code, a la flask. Used badly, well: http://blog.jooq.org/2015/04/15/how-jpa-2-1-has-become-the-new-ejb-2-0/

However, in the case of serializers, i think we should accept/expect a static method, as they nearly always need inheritance, albeit by _.extend today. Using super will make it more clear... That might come as a pr, along with some forensics on the changes since last i really dug into the widgets source... I've been in consumer mode for a while.

Of course, typescript will (soon?) support decorators, so the es7 route could be fruitful. But none of my stuff is typeful yet, so that would constitute even more scale up for me, but is, as you said, the right long term direction.

Will update/link when I've got something going!

On 17:46, Fri, Nov 20, 2015 Jonathan Frederic notifications@github.com wrote:

Yeah I read about that problem regarding backbone recently. I'm glad that you're heading the investigation on this @bollwyvl https://github.com/bollwyvl , and am curious to see what method you choose. Please ping me. Thanks! :)

— Reply to this email directly or view it on GitHub <https://github.com/ipython/ipywidgets/issues/14#issuecomment-158547790 .

— Reply to this email directly or view it on GitHub https://github.com/ipython/ipywidgets/issues/14#issuecomment-158553312.

Brian E. Granger Associate Professor of Physics and Data Science Cal Poly State University, San Luis Obispo @ellisonbg on Twitter and GitHub bgranger@calpoly.edu and ellisonbg@gmail.com

jasongrout commented 8 years ago

I came here to say the same as Brian. I think it's premature right now to rely on decorators.

On Fri, Nov 20, 2015, 17:18 Brian E. Granger notifications@github.com wrote:

The decorator spec hasn't been finalized and the Babel and TypeScript implementations are incompatible. I am -1 on using decorators until the spec is final and all transpilers are doing the same thing.

On Fri, Nov 20, 2015 at 3:12 PM, Nicholas Bollweg < notifications@github.com> wrote:

I'm leaning towards the es7 decorator approach. Used appropriately, i think they offer a really nice visual way to inject just enough code, a la flask. Used badly, well: http://blog.jooq.org/2015/04/15/how-jpa-2-1-has-become-the-new-ejb-2-0/

However, in the case of serializers, i think we should accept/expect a static method, as they nearly always need inheritance, albeit by _.extend today. Using super will make it more clear... That might come as a pr, along with some forensics on the changes since last i really dug into the widgets source... I've been in consumer mode for a while.

Of course, typescript will (soon?) support decorators, so the es7 route could be fruitful. But none of my stuff is typeful yet, so that would constitute even more scale up for me, but is, as you said, the right long term direction.

Will update/link when I've got something going!

On 17:46, Fri, Nov 20, 2015 Jonathan Frederic notifications@github.com wrote:

Yeah I read about that problem regarding backbone recently. I'm glad that you're heading the investigation on this @bollwyvl https://github.com/bollwyvl , and am curious to see what method you choose. Please ping me. Thanks! :)

— Reply to this email directly or view it on GitHub < https://github.com/ipython/ipywidgets/issues/14#issuecomment-158547790 .

— Reply to this email directly or view it on GitHub <https://github.com/ipython/ipywidgets/issues/14#issuecomment-158553312 .

Brian E. Granger Associate Professor of Physics and Data Science Cal Poly State University, San Luis Obispo @ellisonbg on Twitter and GitHub bgranger@calpoly.edu and ellisonbg@gmail.com

— Reply to this email directly or view it on GitHub https://github.com/ipython/ipywidgets/issues/14#issuecomment-158565299.

bollwyvl commented 8 years ago

Between early thanksgivings, I've started over here.

Thanks for the feedback. Let's say, then, that one of the system requirements should be to use ES2015 as published, and no funny stuff. Luckily, there's a plugin for that to keep us honest.

It seems like one of the big advantages of going to the strict spec is being able to take advantage of things tools can infer from the patterns used. I am starting with ESDoc, but am interested in other tools that help us write better code. One thing I haven't found easily is a way to reference the upstream types... everything just shows up as nbextensions/..., etc. But that's still pretty good, as the strings are greppable. There is @external, but then things actually show up in the generated doc, and badly.

On the whole, I am very pleased with the results, and think it's the good level of new techniques to take on before eating the whole typescript elephant. Also, there will categorically be more ES6 developers than TypeScript developers, so this gets us the biggest bang fastest.

Here's the first approach for a model, and the doc it generates.

What I don't like is that the serializers stuff disappears entirely from the esdoc, and is precisely the kind of undocumented stuff that is likely to trip up an extension author. I imagine I could add some stuff like @implements. Making this a static method that returns the serializer object would be nice, and allow us to return _.extend({...}. super.serializers(), but right now I'm working with what I've got.

Similarly, the WidgetManager.register_widget_model also disappears, which is clutch when building things that are created at runtime. Again, I could inject some more @stuff, but I'm trying to see what will give us the least repetition and busy work for the most inferrable information.

Caveats: I am using eslint. There seems to have been this systemic pushback across the jupyter ecosystem about putting linting into the toolchain, so obviously it doesn't have to stay there, but it's helping me learn the new tricks while spooling upon ES6.

Will update as I try other approaches, get testing working, etc. The endgame of this particular repo could be a yeoman generator suite, but I do hope that some of the lessons learned can make their way into the upstream. It should really be a sprintable thing to port the entire codebase, and come out with lovely docs, consistent style, etc. Huzzah!

jdfreder commented 8 years ago

Nice work @bollwyvl , this is basically just what I was hopping we could achieve. I see the workaround for the lack of static members here: https://github.com/bollwyvl/es6-widget-example/blob/master/src/es6/ES6ExampleModel.es6#L14-L21 . I think that's okay. You have to do the same thing when using phosphor-signals in es6 (or have a helper method that does that for you).

jdfreder commented 8 years ago

Caveats: I am using eslint. There seems to have been this systemic pushback across the jupyter ecosystem about putting linting into the toolchain, so obviously it doesn't have to stay there, but it's helping me learn the new tricks while spooling upon ES6.

I'm using jslint with esnext set to true. Have you tried that too? I'm interested in how they compare.

jdfreder commented 8 years ago

What I don't like is that the serializers stuff disappears entirely from the esdoc, and is precisely the kind of undocumented stuff that is likely to trip up an extension author. I imagine I could add some stuff like @implements. Making this a static method that returns the serializer object would be nice, and allow us to return _.extend({...}. super.serializers(), but right now I'm working with what I've got.

I think that there's no substitution for narrative docs. Autogenerated docs, even nice looking ones, don't convey the same level of detail.

bollwyvl commented 8 years ago

Thanks for the feedback!

I'm using jslint with esnext set to true. Have you tried that too? I'm interested in how they compare.

i was a user of jslint/hint, but it bothered me at some point back in the mists of time, and I went to eslint and haven't revisited it in a while.

I think that there's no substitution for narrative docs. Autogenerated docs, even nice looking ones, don't convey the same level of detail.

No doubt, I am all for narrative docs. But here's the value I see in autogenerated ones, even bad looking ones:

For example, serializers isn't really documented anywhere: indeed you have to read the private _deserialize_state and send_sync_message, and the reference unpack_models and resolvePromisesDict to implement your own for something other than widgets, which is really not a crazy thing to want to do.

Custom Widget Message (De)Serialization would be a pretty good doc to read, as part of the Build you a Widget for Great Good series. Lacking that, having it documented with the source would be good enough to get me going.

Turns out I had gitter, and you guys, so it turned out okay, but I digress...

I also consider part of the utility of a documentation generator as a canonical source of URL/Is. Initially, a semantic documentation link is more durable than pointing to line numbers in a repo: consider

http://bollwyvl.github.io/es6-widget-example/docs/class/es6/ES6ExampleView.es6~ES6ExampleView.html#instance-method-className

vs

https://github.com/bollwyvl/es6-widget-example/blob/master/src/es6/ES6ExampleView.es6#L33

The second link will rot (like this afternoon, if i get the time).

However, if someone did write the narrative doc I was looking for, if it linked to the canonical, generated doc, it could be discovered at runtime, a la: https://github.com/jupyter/notebook/issues/99

If I was hovering over myDeeplyInheritedWidget.serializers, I'd love to get a link to the narrative documentation, but if it hadn't been written, I'd take some developer-to-developer shop talk over nothing.

Failing that, even getting links to other notebooks/packages that used/overloaded that function (bqplot, for example, was very useful!) would have saved me a lot of headaches. With that level of annotation, of course, you could also validate how well your narrative docs/examples covered your API.

jdfreder commented 8 years ago

jslint/hint

Sorry, meant to say hint :)

No doubt, I am all for narrative docs. But here's the value I see in autogenerated ones, even bad looking ones:

it's better than nothing it provides good URLs it works with tools the author/team gets some feedback about how much doc has been written

Agreed, didn't mean to imply they don't have value, sorry! Additionally they are great for potential users of the API to come and see what it looks like without reading code.

I also consider part of the utility of a documentation generator as a canonical source of URL/Is. Initially, a semantic documentation link is more durable than pointing to line numbers in a repo: consider

Also a good point.

What do you think about the annotated source rendering? ie http://backbonejs.org/docs/backbone.html . Generated by http://jashkenas.github.io/docco/

bollwyvl commented 8 years ago

What do you think about the annotated source rendering? ie http://backbonejs.org/docs/backbone.html . Generated by http://jashkenas.github.io/docco/

Docco/pycco's great for reading, and even better for writing... (especially when live-updating with watch, etc)... but doesn't actually create named anchors that could be used as URIs, and won't help anybody's tooling. The backbone example is all section-1 through section-255, etc. So you're back to, "go grep this document" to learn what you need.

This works for backbone! It's one file. And it almost perfectly leverages underscore to write as little code as possible. Backbone is also nearly a work of art with a really strong typographic design aesthetic. Written in coffeescript, it would be... almost nothing. And it brings very few opinions.

I don't think we're there yet, and I think the way people will want to use widgets would benefit from leveraging more structure and more explicit documentation of our opinions... which are many.

All this being said, "literate" (it's not true literate, if you can't reflow stuff) and machine-readable doc could probably co-exist in source: the narrative doc in // and the javadoc in /** ... */... I think this was discussed at some point on gitter. All this doc in the code gets heavy... but I guess get an editor that can collapse comments helps. I could even imagine son-of-docco-and-esdoc that was n-panel and toggled between multiple views.

In terms of delivering all that narrative to the browser to support exploratory computing(!): if we are picking up a transpiler, we might as well go whole-hog, and do a highly optimized, uglified build (every file gets loaded every time anyway, now... might as well save 20 requests), but then include an external source map.

Lots to do!

jasongrout commented 8 years ago

Done in #627.