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

Consider JSX-like as React Native #15922

Closed
JonathanSum opened this Issue Mar 25, 2018 · 148 comments

Comments

Projects
None yet
@JonathanSum
Copy link

JonathanSum commented Mar 25, 2018

For code that builds a UI has to be readable. I understand that Dart is kind of like a simple version of Java, but it is not really a programming language for building a UI. For example, it doesn't have a closing tag. As a result, It is very hard to build a picture in mind with this unreadable code.

Moreover, Flutter was inspired by React. How can Flutter doesn't have JSX but has this kind of unreadable code? I am very scared that Flutter is going to die very soon as the early days of AnglurJs.

I understand people who work in Google are smart, but we also have some people who are not really smart choose React instead of Dart, and this is one of the reasons why Dart was dead in the past.

@JonathanSum JonathanSum changed the title Come on, Let's face this. This flutter framework really need JSX-like syntax Come on, Let's face this. This flutter framework really needs JSX-like syntax Mar 25, 2018

@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 25, 2018

This has been asked for a long time:
#11609
Functional prototype developed:
https://spark-heroku-dsx.herokuapp.com/index.html
That shows the alternative and some benefits...


The current issue with DSX is about proper integration with Flutter tools as to provide a great developer experience with debugger, auto-complete, etc. working on .dsx files.

Telling users that they can use DSX but can't use debugger or enjoy auto-complete is a non starter for me. If anybody wants to help, what I need is to figure out a way to add full preprocessing support (with source map) to Dart Tools and VS Code Dart plug in. Once the tools support that DSX or any other transpiling language (any language that is a superset of Dart but compiles everything down to Dart) would just work.

If you can and would like to help, let me know.

@JonathanSum JonathanSum changed the title Come on, Let's face this. This flutter framework really needs JSX-like syntax Come on, Let's face this. This flutter framework really needs JSX-like syntax as what React-Native has. Mar 26, 2018

@escamoteur

This comment has been minimized.

Copy link
Contributor

escamoteur commented Mar 26, 2018

I cannot agree. Especially using a IDE like Dart Code you get virtual closing tags which makes readin way easier. With Dart2 where you can omit new it will even get better.

Also I find it discourages you to build too big Widget trees without deconstruct it into smaller easier to maintain widget classes.

@JonathanSum

This comment has been minimized.

Copy link
Author

JonathanSum commented Mar 26, 2018

I use Android Studio. I don't even see a virtual closing tag. Even though we have a virtual closing tag, it is more complicated than HTML that everyone hates. Dart is just a programming language. People in Google don't understand the importance of simplification.

@JonathanSum

This comment has been minimized.

Copy link
Author

JonathanSum commented Mar 26, 2018

close

@carl2013

This comment has been minimized.

Copy link

carl2013 commented Mar 26, 2018

I don't think I would like a JSX-like syntax either but yeah, I use IntelliJ and something needs to be done with the tooling so that the UI code is easier to understand.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 26, 2018

Also I find it discourages you to build too big Widget trees without deconstruct it into smaller easier to maintain widget classes.

I don't see how this is any different than with JSX... as the tree gets larger you can break into smaller sub-trees with both.

I don't think I would like a JSX-like syntax either but yeah, I use IntelliJ and something needs to be done with the tooling so that the UI code is easier to understand.

and it should be easy to read on all platforms and not only Intellij; I mean it should be easy to read on Bitbucket when reviewing code; and it should also be valid when using any editor; I mean with these 'comment annotations' what happens if someone using 'vi' types a different comment in there?

@zoechi

This comment has been minimized.

Copy link
Contributor

zoechi commented Mar 26, 2018

This is a dup of the locked down #11609
@sethladd ?

@sethladd

This comment has been minimized.

Copy link
Contributor

sethladd commented Mar 26, 2018

Apologies, you should be seeing the "virtual closing tags" in IntelliJ and Android Studio.

cc @devoncarew to verify which version turned that on, or if the user needs to opt-in ?

We thank you for your comments re: JSX-like syntax. We believe there is opportunity across the language, our tools, and plugins to make editing UI code easier.

This does dupe #11609 but I'd like for @devoncarew or @mit-mit to add a note about how to turn on "virtual closing tags", if possible.

Thanks!

@devoncarew

This comment has been minimized.

Copy link
Member

devoncarew commented Mar 26, 2018

@JonathanSum, the closing labels aren't available in Android Studio 3.0 unfortunately. You'll need at least IntelliJ 2017.3 or Android Studio 3.1. Android Studio 3.1 is currently in the release candidate stage, and we plan to release a flutter plugin with support for it tomorrow.

Irrespective of the conversation around a JSX like syntax, we do want to work towards making it easier to write UI code in Dart, in both IntelliJ / Android Studio and in VS Code. That's initially the closing label work, but also the recent Flutter Outline view. That shows the structure of your build() method in an outline view, and allows you to navigate the widgets and more easily see their parent / child relationships. That's currently available in IntelliJ - we do expect to be able to bring it to VS Code as well.

@NathanaelA

This comment has been minimized.

Copy link

NathanaelA commented Mar 26, 2018

@zoechi - This might be a dup; but the other thread got heated, and locked. So their is no way to contribute to that conversation. I don't think you should close this thread as a dup just because you don't like people asking for a feature. This should probably be the new thread for responses for new people coming and requesting JSX support (or similar functionality).


@sethladd - Please do not lock this thread; I do think having community discuss pro's and con's on alternative layout methods is useful. I would have participated in #11609 had it not been locked.


I come from a NativeScript background. I have to say this is one area where I do feel NativeScript is considerably easier to use than Flutter. I can get a fairly complex screens working in less than 5 minutes and easily iterate the design quickly. Then add the code that runs the screen.

In NativeScript we actually have the following files:

  • screen.js / screen.ts (.ts is transpiled into .js if you prefer typescript). This is the main logic for the screen that you are displaying.
  • screen.css (or screen.android.css and/or screen.ios.css) which is a much more limited version of CSS but supports things like height, width, color, background, etc. Most the time a single css file is only needed, but occasionally if you are doing something weird you might separate your css for android and ios. It has full support for Classes, Elements, and id's So I can do TextArea.Login #Password and it actually will limit itself to just that specfic element chain.
  • screen.xml (Again or screen.android.xml and/or screen.ios.xml) - This is the screen layout. You CAN code the layout in JS if you want (basically like flutter); but the XML is so so much easier. Example:
<Page onLoad="loadme">
    <ActionBar title="Blah"><NavigationButton click="back" title="Back"/></ActionBar>
    <StackLayout>
      <Label text="Hi" id="Hi" style="color: red"/>
     <Label text="{{name}}" class="name"></Label>
     <Button text="Click Me" tap="clicker"/>
    </StackLayout></Page>

The interesting thing is that ActionBar is a specific page only component (i.e. it is specific to only Page); so basically what happens is the XML parser See's page; creates a new Page Element; then creates a ActionBar component which it then runs a builderChild function on the Page component; the page component overrides the default builderChild and looks to see if the child is a ActionBar; if it is; then it internally assigns it to the proper variable; otherwise the rest is passed through parent/super which then assigns it to the "child" or "children" components automatically. The build system is incredibly versatile in that each component can use either the parent's builderchild function or override it to do extra items like support <Label>Hi</Label> and assign that to the Text value automatically. This makes layout incredibly easy to get up and running without any code.

Because most editors have good XML editing capability it is automatically colorized and with the proper xsd definition intellij (& vscode) does automatic checking and limited context support.

Now technically everything is actually a JavaScript component; so you can do all this manually (like what Flutter does); but I find the easy of laying out a screen is trivial in NativeScript. And you don't need the JS or CSS when you first start; then you can add the CSS (typically you don't hard code in the layout the css based properties; but you can if you want).

The nice thing about this; is it allows Web developers to jump right in with very little (if any) retraining. In fact; because of its flexible renderer and being JS based -- NativeScript actually support Angular and Vue -- so that you can actually share close to 95% of the code base between web, and your mobile app if you use Angular or Vue. Since it uses Native OS components like react native (not a webview like cordova); it really is a decent cross-platform system (that is imho better than React Native) . However, I can see where there are some strengths that Flutter has that makes it a good complimentary tool for some mobile development as their are some apps that NativeScript is worse at and some it is still the much better for and based on the responses to my issues from Ian; will stay the considerably better tool for in those areas.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 26, 2018

Better to open that locked thread and copy these comments there so we have a history of full discussions.

@zoechi

This comment has been minimized.

Copy link
Contributor

zoechi commented Mar 27, 2018

@JonathanSum it's not about whether anyone wants or doesn't wants the feature,
it's whether this is the place to have a heated discussion about it. I guess reddit or similar are better places.

@NathanaelA

This comment has been minimized.

Copy link

NathanaelA commented Mar 27, 2018

@cbazza - I don't disagree; but you have to be very careful in the future to not insinuate things about people. That just inflames the discussion, no matter how idiotic you believe they are being.

@zoechi - Actually I believe any discussion about a new feature should be here. History should be maintained so that when John Doe comes a month from now and searches about XYZ feature he can 👍 an existing feature and/or contribute to it.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 27, 2018

I don't think that thread is really locked for this long because of my comments. If what I said was so bad how come I can comment on everything else, like for example this thread?

The thread is locked because the Flutter team has no interest in doing this and just want people to stop talking about it.

@sethladd

This comment has been minimized.

Copy link
Contributor

sethladd commented Mar 27, 2018

Let's please keep the discussion in this issue focused on use cases and examples for a JSX-like feature.

@escamoteur

This comment has been minimized.

Copy link
Contributor

escamoteur commented Mar 27, 2018

Actually if NativeScript is that good, why bother with Flutter at all instead of trying to make Flutter NativeScript like.
I'm coming from an XML based Platform (Xamarin Forms) and thought in the beginning it might be more difficult to design in code but that's not the case.
In the contrary it makes is very easy to break down your design in separate classes which are easy to maintain.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 27, 2018

JSX is designing in code !!!

@sethladd

Let's please keep the discussion in this issue focused on use cases and examples for a JSX-like feature.

OK, Let's talk about my DSX design which can be viewed here:
https://spark-heroku-dsx.herokuapp.com/index.html

It provides a direct mapping to the current way widgets are built and yet provides a JSX like flavour that is very lightweight and familiar to React developers. Is there anything missing in this design? Can this design generate all possible widgets in the wild?

@mrmcq2u

This comment has been minimized.

Copy link

mrmcq2u commented Mar 27, 2018

Rule of thumb, if you feel one exclamation mark isnt enough you should probably step away from the keyboard and take a break.

@SirComputer1

This comment has been minimized.

Copy link

SirComputer1 commented Mar 27, 2018

I'm a newcomer to Flutter, having only some experience with Android and Java, and I must say I find what Flutter offers far better than what is being proposed here. I tend to find that XML is ugly and unwieldy. It's so much more beautiful to have a singular closing character, rather than a sea of that makes my code 5x longer, a hatred of mine when editing Android XML, and just virtual closing tags which the vast majority of IDEs which people use support. This is incredibly useful when designing longer structures. The neat nesting XML provides just doesn't outweigh the rest of the disadvantages, in my opinion, especially when 'child:/children:' do almost as good of a job. Dart is incredibly clean, and it is a reason I like it so much. I would be incredibly disappointed if this was to be ruined.

I know that React does it like this, but last time I checked, this place says Flutter. Just because React does it doesn't mean we have to - you're not the only ones jumping ship to here! I very much agree with all the points @escamoteur made. I'm not seeing the point in adding yet another language that people need to handle when using Flutter. We're already using Dart to program most of it, we don't need a load of other things to master! Consistency and simplicity must be valued.

@lukaspili

This comment has been minimized.

Copy link
Contributor

lukaspili commented Mar 27, 2018

Some remarks from your DSX vs generated Dart snippets:

  1. Subjective: I don't see any great readability gains. Verbosity is similar - if not a tad longer. Dart IDE plugin provides auto closing tags, which mirrors declarative markup closing tags. If JSX is design in code, then I don't see how widgets in Dart is not.

  2. Multiple properties in <vars>

@<vars>
var textStyle = {
    "textDirection": "TextDirection.ltr",
    "textAlign": "TextAlign.center",
    "overflow": "TextOverflow.ellipsis",
    "style": "new TextStyle(fontWeight: FontWeight.bold)"
};
</vars>@

Being able to define global styles mixing several properties is a nice idea.
However when I'm looking back at my modest flutter experience, I don't see where I would use these.

For Text it seems most of what I need to reuse is defined in TextStyle, rather than a mix of several properties. Maybe you can find another example than Text where that's not the case.

Looking at TextStyle, I find the current immutable + copy() to be great for reusing and composing in Dart:

class Style {
  static const TextStyle avenirNextMedium =
      const TextStyle(
         fontFamily: 'Avenir Next', 
         fontWeight: FontWeight.w500,
      );

  static TextStyle title =
      avenirNextMedium.copyWith(
        color: ColorKit.blue, 
        fontSize: 45.0,
      );
}

new Text(
  'Hello',
  style: Style.title,
),

new Text(
  'Hello2',
  style: Style.title.copyWith(
    color: ColorKit.red,
  ),
),

For reusable Container sharing a same style, I think that creating a custom stateless widget works better than an external defined <vars>. Most of the time, I want also a padding, an ink, a gesture listener or a shadow.

For any of those cases, I would need to compose Container with another widget: Material, Padding, Center etc. So if I have to create a custom reusable "container" widget anyway, I don't see much gain to have an external <vars> style that would just define the properties of a single widget in my reusable widgets hierarchy.

I don't see Flutter's "everything is a widget" work well with "multiple properties" styles.

  1. Not highlighted in your current DSX examples: How would you code an interface with dynamic widgets? Meaning: how to show or not show some widgets depending on a condition.

When doing design in Dart it's easy and convenient to add or not a particular widget into children.
It's also very convenient to dynamically wrap a widget with another. It makes the build() function fluent and easy to understand.

    var children = <Widget>[];
    if(a) {
      children.add(wa);
    }
    
    var wb = Text();
    if(b) {
      wb = Padding(child: wb);
    }
    
    children.add(wb);
@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 27, 2018

@SirComputer1 the DSX proposal is an addition, the current way doesn't change so if you don't like it, don't use it, continue as you are today.

The <var> thing was only done for the demo because I didn't want to parse full Dart. The final solution would not include <var> but would use any dart variable. Also the '@' was only done for the demo to make parsing easy. Final solution would not include it.

Don't forget that anything else on the file is your normal Dart code, so you can use that for everything else.

    var children = <Widget>[];
    if(a) {
      children.add(wa);
    }
    
    // You can mix and match both
    var wb = <Text/>;
    if(b) {
      wb = Padding(child: wb);
    }

    // or
    var wb = Text();
    if(b) {
      wb = <Padding> {wb} </Padding>;
    }
    
    children.add(wb);

    children.add(
      <Center>
          {sayHello == true ?
             <Text ['Hello, world!']/>
          :
             <Text ['Good bye']/>
          }
      </Center>
    );

Let's stop comparing DSX with the current way, one is not competing with the other. Some people will prefer JSX and this thread is for them. What I want to know is how can I improve DSX to handle things that it won't work for.

@NathanaelA

This comment has been minimized.

Copy link

NathanaelA commented Mar 27, 2018

@escamoteur - I don't tend to use a hammer as a screw driver. I evaluate the different technologies and use the proper one for the proper use case. That doesn't mean their isn't things can could be changed for the better in each of the platforms. 😀

For example; third party plugins integration. NativeScript is truly king over every single other cross platform. Nothing else even remotely comes close to NativeScript; and third party integration. I have a client asking about using https://github.com/vipulasri/Timeline-View . Flutter virtually impossible; NativeScript give me a couple hours and it will work just like any other NS control probably even with fully working data binding. On the flip side flutter has some serious strengths where NS flags...

Use the proper tool for the job. 😀


I do tend to like the XML based screen layout; but I do understand why people don't. Adding the ability for XML based building does NOT mean eliminating the existing method; it is just complementary; choice. For those of you who didn't bother reading, I can do the same chain of calls in NS that we do in flutter; but using xml is a lot less typings and easier to me to read. Everybody has their preferences...

I have actually thought about adding a XML based renderer to Flutter as a POC; but I haven't had the spare time. I just wanted to contribute to the conversation and say I would like to see this move forward; but I actually do not expect the core team to work on it. I think NS XML format could be done as community projects where those of us who care (i.e. probably me 😀) would be willing to do the work on them. However, my biggest concern @sethladd -- is if I spend a lot of time on a patch; will it be rejected because someone on the core team absolutely opposes this ability. That is what I would like to nail down first before I spend any time on this...

@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 27, 2018

@NathanaelA Fantastic perspective !!!!!!! and look I used lots of exclaimation marks ;-) You literally nailed it on the head.

Yes, I can do DSX but I need a way to integrate it in the current Flutter build system so I need commitment from the current Flutter team before I move forward. IDE integration is virtually trivial on VS Code but not so much with Intellij (unless Google has access to Intellij JSX support).

@JonathanSum

This comment has been minimized.

Copy link
Author

JonathanSum commented Mar 28, 2018

@zoech, No! I think this is an issue. I remember developing an android app with native Java and XML. We still use XML for UI language part. I think using Dart for logic and UI is kind of odd, and this problem is kind of obvious. furthermore, I just hope Google is going to add the UI idea of React into the flutter. The UI part of React is very powerful and concise.

@zoechi

This comment has been minimized.

Copy link
Contributor

zoechi commented Mar 28, 2018

@JonathanSum I have seen many comments about this.
For me it still looks like something people want because they are reluctant to change their habits, not because it's a benefit for the platform.

@yuu2lee4

This comment has been minimized.

Copy link

yuu2lee4 commented Mar 28, 2018

Some people like jsx, Some people dont. Why dont support the two ways to implement UI. You can write jsx-like syntax,and it will finally be comeplied to flutter native syntax,why not support?

@zoechi

This comment has been minimized.

Copy link
Contributor

zoechi commented Mar 28, 2018

@cbazza

This comment has been minimized.

Copy link

cbazza commented Mar 28, 2018

@zoechi

For me it still looks like something people want because they are reluctant to change their habits

This is a fair observation but wouldn't it be better for Flutter to be an enabler and remove as much friction as possible for people (outside Google) to adopt Flutter? This gate-keeping behavior is not winning hearts and minds of developers.

@yuu2lee4

Some people like jsx, Some people dont. Why dont support the two ways to implement UI. You can write jsx-like syntax,and it will finally be comeplied to flutter native syntax,why not support?

Excellent question. Given that I am doing all work on DSX, which is just like JSX, and @Hixie personally sent me email excited about the progress, I don't see why not support it, I don't see why not extend a hand and say 'What can I do to help you? What is blocking you to do this?'

@rrousselGit

This comment has been minimized.

Copy link
Contributor

rrousselGit commented Oct 11, 2018

I don't want to have to write closing tags. It's a pain in JSX/html/xml. Especially when I want to refactor.
I think the virtual closing tags is pretty neat. It seems like a good compromise between both worlds.

If we really need some improvements here I think we can continue exploring on the IDE side. For example, vscode provides the following panel:

screen shot 2018-10-11 at 01 31 33

(Pretty sure Android Studio has the same)

Instead of stopping at the focused method, we could add constructors nesting too.
So that when hovering a specific class we'd get the following UI:

lib > main.dart > Foo > build > Container > Center > Text 

If it's about separating visually widgets from other kind of content, the IDE can do it too again.

We can have a different syntax hightlighting for widgets. Instead of the usual color used for classes, we can have a specific color for widget subclass


If it's about editability, then Flutter already provides all the tooling you need.

There are quite a few refactoring options, including:

  • Wrap into new widget
  • Remove widget
  • Swap widget with child
  • Swap widget with parent

With these in mind, you don't have to deal with parenthesis anymore.


In all honesty, I spent hours on a daily basis playing around Flutter for months. And I haven't felt any lack in readability or any disconfort in writing nested widgets.
While in comparison, I've used React for just as much and there are some stuff that frustrate me.

@Rockvole

This comment has been minimized.

Copy link

Rockvole commented Oct 11, 2018

@rrousselGit - those refactoring options you have sound useful. I don't see them on Android Studio 3.2.
I thought Android Studio would provide the best features for Flutter development.

@pulyaevskiy

This comment has been minimized.

Copy link
Contributor

pulyaevskiy commented Oct 11, 2018

@Rockvole

Here is a screenshot from Android Studio:

image

Activated as a quick-fix Option+Enter (macOS).
I use these all the time, super helpful.

On the topic: it seems that Flutter team is exploring options for "UI as code" and we might get more improvements on this front sooner or later. Though ideas of @StokeMasterJack sound interesting.

@StokeMasterJack

This comment has been minimized.

Copy link

StokeMasterJack commented Oct 11, 2018

@Rockvole Great minds think alike!

@cbazza

This comment has been minimized.

Copy link

cbazza commented Oct 11, 2018

@StokeMasterJack

Nice reply !!!

There are two reasons JSX makes more sense for React:

  1. Data structure: On the web, JSX matches exactly the thing being generated (HTML DOM nodes). In flutter, we are generating Widget instances.

The power of JSX is not on generating HTML/DOM nodes, it is in managing component hierarchies; React Native doesn't have HTML/DOM nodes right?

  1. Familiarity: People are used to looking at html code. But the DSX proposal deviates from JSX/XML just enough to invalidate this point.

Just like above, it is not about HTML code, it is about a syntax that becomes clearly separate from the imperative constructs of the host language and screams declarative markup for building tree hierarchies.

I am not a fan of your proposal or Kotlin's because it looks like a hack done to avoid doing a proper design. Instead of designing a DSL that looks distinct, now I have to look at the code and try to figure out what it does; The syntax looks ambiguous. There are benefits for separating imperative and declarative constructs; 3rd party tools can easily locate XML markup inside code for example.

@Rockvole

I would use a JSX-like syntax just to get the end tag notation

Good to know ;)

@rrousselGit

I don't want to have to write closing tags.

You don't have to; WebStorm for example auto generates the closing tag and it even renames the open or closing tags as you edit the other. Really great editor functionality that others should follow (looking at you 'VS Code').

In all honesty, I spent hours on a daily basis playing around Flutter for months. And I haven't felt any lack in readability or any disconfort in writing nested widgets

I hope you can appreciate that your experience does not reflect everybody else's experience. With the tooling, writing is not as painful as reading the code. Go to github to read other people's code and you will notice that reading is a pain, the code is too verbose and long with nested structures. It looks like when promise-chains were used before async/await showed a better way. Also it feels like declarative techniques are less important than imperative ones; I mean why isn't there declarative vector graphics constructs? instead I have to use imperative calls to Skia for vector graphics drawing for example.

@rrousselGit

This comment has been minimized.

Copy link
Contributor

rrousselGit commented Oct 11, 2018

You don't have to; WebStorm for example auto generates

Vscode does that too. But that it still not perfect. Especially in the refactoring step when moving things around.
I think virtual tags provides a much smoother experience here.

I hope you can appreciate that your experience does not reflect everybody else's experience

For sure ! I just wanted to point out it may be more of an inexperience with the tooling then an actual lack 😄

Go to github to read other people's code and you will notice that reading is a pain, [...]

I don't quite see how your arguments here are related to the topic.
The problem you listed comes from bad practices, not bad syntax. It's not Flutter's fault if peoples want to make a 500 long widget tree.

@Rockvole

This comment has been minimized.

Copy link

Rockvole commented Oct 11, 2018

@pulyaevskiy - thanks for the useful tip, on Linux the quick fix is Alt-Enter. Not a very easy feature to discover, I scoured the top menu options but it seems to be nowhere except by magical keypress :)

@cbazza

This comment has been minimized.

Copy link

cbazza commented Oct 11, 2018

I think virtual tags provides a much smoother experience here.

Do these virtual tags show up on source file in github for example?

I don't quite see how your arguments here are related to the topic.

Basically the language could provide constructs to make things less verbose as I mentioned in the promises vs. async/await example. In Flutter Widget constructors are enormous and a lot of times they take a lot of parameters; with DSX you can use the spread operator for example to compress a 10 line constructor into a 1 line constructor and hence you can still have the complete tree hierarchy visible with less noise around it. This makes reading the code easier and allows clean separation of style from tree structure for example. I am not saying this can't be done by re-structuring your Dart code but it can be done without much effort or re-structuring things around. You don't need to fit to the limitations of the language, the language fits to you.

The problem you listed comes from bad practices, not bad syntax.

Before async/await, best practices were to use promises instead of crazy event callbacks everywhere. Using promises causes readability problems that were addressed by async/await. It is basically the same thing just syntactic sugar but async/await is clearer when reading someone else's code.

@birkir

This comment has been minimized.

Copy link

birkir commented Oct 17, 2018

This is a terrible example @woodstream

Update: Just to make my point and not just bashing out words without any arguments. The DSX equivalent is just as long... This is nothing to do with line count, or HTML.

class MusicImage extends StatelessWidget {

  TextStyle titleTextStyle = TextStyle(
    fontWeight: FontWeight.w800,
    letterSpacing: 0.5,
    fontSize: 20.0
  );

  Container titleText = (
    <Container height={116.0} padding={EdgeInsets.all(10.0)}>
      <Text style={titleTextStyle}>title</Text>
    </Container>
  );

  TextStyle authorTextStyle = TextStyle(
    fontWeight: FontWeight.w800,
    letterSpacing: 0.5,
    fontSize: 10.0,
  );

  Container music = (
    <Container
      height={40.0}
      decoration={BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.all(Radius.circular(8.0))
      )}
      padding={EdgeInsets.fromLTRB(0.0, 5.0, 5.0, 0.0)}
      margin={EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 0.0)}
    >
      <Stack>
        <Row>
          <Container
            height={30.0}
            width={30.0}
            decoration={BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(8.0))
            )}
            margin={EdgeInsets.fromLTRB(5.0, 0.0, 5.0, 0.0)}
          >
            {Image.asset('images/bg2.jpg')}
          </Container>
          <Column>
            <Text>music</Text>
            <Text style={authorTextStyle}>author</Text>
          </Column>
        </Row> 
        <Align alignment={FractionalOffset.centerRight}>
          <Icon icon={Icons.play_arrow} />
        </Align>
      </Stack>
    </Container>
  )

  @override
  Widget build(BuildContext context) {
    return (
      <Container
        height={168.0}
        margin={EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0)}
        decoration={BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(8.0)),
          image: DecorationImage(
            image: new AssetImage('images/bg.jpg'),
            fit: BoxFit.cover,
          ),
        )}
      >
        {titleText}
        {music}
      </Container>
    );
  }
}
@TareqElMasri

This comment has been minimized.

Copy link

TareqElMasri commented Nov 27, 2018

As a React developer, I think what this community needs to do is to provide this feature themselves and when the developers start to adapt it and actually use it; the main contributors will be forced then to adapt it natively as well. I'm a React developer and I have a lot of issues dealing with how UI is written in flutter, I would love to move to flutter but the syntax isn't helping, I would even research of how to implement the JSX-like syntax myself, as said before "It's nice to have the option".

@andrewfluck

This comment has been minimized.

Copy link

andrewfluck commented Dec 8, 2018

I think the one of the main reasons people are pushing against this is they can't imagine them using it. Truth is, you really don't have to, just like people use (comparing to react) React.createElement(Component, {}, null) as opposed to <Component /> If this is implemented, this will draw people to use Flutter in the first place, and thats what we really want. A large community dedicated to Flutter with support from each other. If it's not the kind of syntax you would use, oh well. But tons would prefer a JSX like notation as opposed to the current method.

@filleduchaos

This comment has been minimized.

Copy link
Contributor

filleduchaos commented Dec 18, 2018

Personally I think SGML and its derivatives are just plain ugly. If we're doing a DSL, why not one with QML-like syntax?

I also think some of the pro-DSX points are conflating features of Javascript as a language (that Dart as a language does not have) and features of JSX as a DSL. For instance,

Basically the language could provide constructs to make things less verbose as I mentioned in the promises vs. async/await example. In Flutter Widget constructors are enormous and a lot of times they take a lot of parameters; with DSX you can use the spread operator for example to compress a 10 line constructor into a 1 line constructor and hence you can still have the complete tree hierarchy visible with less noise around it.

That's not a feature DSX would magically grant, that's a feature JSX has because Javascript has it. Dart as a language could gain the spread operator (rather unlikely IMO), in which case you'd be able to use it with constructors and other function calls without needing a special DSL on top of things. It's also a feature that works largely because Javascript's objects, hashmaps and arrays are all essentially the same thing, which is most definitely not the case with Dart and is almost definitely never going to change.

And that I think is the problem that a lot of the people against the proposal have even if it's not vocalized - it's essentially a request to have Dart behave (or pretend to behave) like Javascript, and while there are some pros the fact is that they simply are different languages that have been diverging more and more since the early days of Dart 1.

Edit: Which is not to say that a markup/modeling DSL for UI is entirely a bad idea. It's honestly not, but I think that the inspiration for it should come from languages/frameworks that are a bit more similar to Dart/Flutter (in typing paradigm as well as other semantic details - I'm not talking about plain syntax) than Javascript is.

@mraleph

This comment has been minimized.

Copy link
Contributor

mraleph commented Dec 18, 2018

Dart as a language could gain the spread operator (rather unlikely IMO)

In fact spread for collections is already specified and ready for implementation, see Spread Collections and the whole "Language funnel" for more info about upcoming Dart language features.

@filleduchaos

This comment has been minimized.

Copy link
Contributor

filleduchaos commented Dec 18, 2018

@mraleph I was talking about the spread operator specifically in use in function/constructor calls and with objects, not just with Lists or Maps - that's what I think is unlikely. Sorry if that wasn't clear!

(I'm vaguely aware of that proposal, but the last I checked it you can't just spread a Dart Size(10, 10) the way you can spread/destruct a Javascript Size { width: 10, height: 10 }, or spread a list/map of arguments into a normal function call (not using Function.apply, which would sacrifice type safety))

@cbazza

This comment has been minimized.

Copy link

cbazza commented Dec 18, 2018

@filleduchaos

Personally I think SGML and its derivatives are just plain ugly. If we're doing a DSL, why not one with QML-like syntax?

Because a lot of people, unlike you, don't think it is ugly and rather prefer it. You don't have to have much vision to see all of the enthusiastic React developers out there.

JSX/DSX brings markup into the host language Javascript/Dart in a way that enhances the host language and enables all programmatic language contructs on the markup. Very simple and powerful stuff.

That's not a feature DSX would magically grant, that's a feature JSX has because Javascript has it.

Not true at all; DSX can implement spread by itself, it doesn't need Dart to support it. It would be nice if it did but not a requirement. That's the beauty of transpiling from a higher language into Dart, the higher language doesn't need to be constrained by Dart.

My prototype online DSX transpiler processes spread operator just fine, check it out:
https://spark-heroku-dsx.herokuapp.com/index.html

And that I think is the problem that a lot of the people against the proposal have even if it's not vocalized - it's essentially a request to have Dart behave (or pretend to behave) like Javascript, and while there are some pros the fact is that they simply are different languages that have been diverging more and more since the early days of Dart 1.

Stop thinking about what current Dart is and focus on what it could be by taking the best ideas from all of the other languages out there.

I think that the inspiration for it should come from languages/frameworks that are a bit more similar to Dart/Flutter (in typing paradigm as well as other semantic details - I'm not talking about plain syntax) than Javascript is.

Typescript is typed and supports JSX. The closest UI framework to Flutter is React, and guess what React took off because of JSX. Please do come up with something better than JSX/DSX and if you do, people will stop asking for JSX/DSX but I haven't seen anything out there that I consider better so right now JSX is the state-of-the-art.

It is nice to see though that the Dart language people are taking the best ideas from other languages like Python (list & dictionary comprehension).

@filleduchaos

This comment has been minimized.

Copy link
Contributor

filleduchaos commented Dec 18, 2018

@cbazza

Because a lot of people, unlike you, don't think it is ugly and rather prefer it.

And vice versa. Why this one syntax and not any other, especially when it doesn't really have a strong relationship with the language? (With the Android SDK, Java and XML had had a relationship for years. Ditto with Javascript and HTML, which JSX strongly resembles. DSX as proposed would be bringing SGML syntax based on it making sense for other languages but not necessarily for Dart).

JSX/DSX brings markup into the host language Javascript/Dart in a way that enhances the host language and enables all programmatic language contructs on the markup. Very simple and powerful stuff.

Not true at all; DSX can implement spread by itself, it doesn't need Dart to support it. It would be nice if it did but not a requirement. That's the beauty of transpiling from a higher language into Dart, the higher language doesn't need to be constrained by Dart.

It's rather interesting to look at these two statements in juxtaposition, because they just go to prove my point. JSX is great (for Javascript) specifically because of its simplicity - it's simply sugar over what are already JS language constructs, it doesn't really implement any special semantics itself. You rightly praise that simplicity, then go on to say that DSX should implement semantics by itself independent of the target language apparently without recognizing 1) how much more work that is to ask for, and 2) how it entirely defeats the point of being a simple but powerful DSL.

My prototype online DSX transpiler processes spread operator just fine, check it out:
https://spark-heroku-dsx.herokuapp.com/index.html

I have seen your transpiler before, and while it is impressive work it in no way comes close to processing the spread operator in the way that Javascript as a language (and thus JSX) does by default. As has been mentioned, spreading (and eventually destructuring) collections is not very much at odds with Dart, and in fact is in the pipeline to be implemented. Spreading and destructuring any object (which, unlike in JS, are very much are not the same thing as Maps) is, and your transpiler doesn't appear to handle that either (and in fact requires putting arguments inside Maps, which is rather unidiomatic and unusable Dart (cannot be interacted with in a decently type-safe manner, for instance)).

Stop thinking about what current Dart is and focus on what it could be by taking the best ideas from all of the other languages out there.

Sure. But of the languages out there for Dart to lift from, personally JS isn't very high on the list - I honestly think trying to be too much like JS (for the sake of interoperability) crippled Dart in its early days.

I would love a UI DSL, sure. But that DSL should be idiomatic for Dart, not lifted wholesale from a semantically different language because of popularity alone.

And I would also like for people to stop conflating what Javascript does with what JSX the DSL does, because some of the benefits mentioned are actually language-level feature requests in disguise. To continue with the spread operator, if Dart as a language actually did support the full range of the operator as it is in JS then I don't see how return <SomeWidget {...someArgs, arg: newValue } />; is preferable to read than return SomeWidget(...someArgs, arg: newValue); or QML-like return SomeWidget { ...someArgs, arg: newValue }; unless one has some attachment to SGML.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Dec 18, 2018

@filleduchaos

Why this one syntax and not any other, especially when it doesn't really have a strong relationship with the language? (With the Android SDK, Java and XML had had a relationship for years. Ditto with Javascript and HTML, which JSX strongly resembles. DSX as proposed would be bringing SGML syntax based on it making sense for other languages but not necessarily for Dart).

Stop pairing up things you think go together (and have a relationship) and focus on picking best ideas regardless of where they come from. You are kind of artificially segregating things when there is no need for it.

I am picking JSX syntax because it is well regarded in React and that's what React people expect and want. This ticket is about that, if that is not for you, don't use it.

It's rather interesting to look at these two statements in juxtaposition, because they just go to prove my point. JSX is great (for Javascript) specifically because of its simplicity - it's simply sugar over what are already JS language constructs, it doesn't really implement any special semantics itself. You rightly praise that simplicity, then go on to say that DSX should implement semantics by itself independent of the target language apparently without recognizing 1) how much more work that is to ask for, and 2) how it entirely defeats the point of being a simple but powerful DSL.

Whether it implements new semantics or not, it is irrelevant. Simplicity comes from its usage. If it is easy for users/developers to use, they will use it. Users/Developers don't care about how complex internally something is (or how much work it was to do), they just care how simple it makes their life and improves their code.

I have seen your transpiler before, and while it is impressive work it in no way comes close to processing the spread operator in the way that Javascript as a language (and thus JSX) does by default.

My intention with spread on DSX was just to spread attributes and not a complete JS implementation of spread. It works just fine for what it is and it has no type-safe issues at all. Type checking/correctness occurs when Dart compiles what DSX generates.

crippled Dart in its early days.

What cripped Dart in the early days was not providing simple JS interoperability so current JS libraries could be used easily with Dart code (and vice-versa). Also this is the exact same reason why Typescript succeeded where Dart failed.

I would love a UI DSL, sure. But that DSL should be idiomatic for Dart, not lifted wholesale from a semantically different language because of popularity alone.

Popularity dictates everything. Best ideas are best ideas because they become popular because lots of people appreciate its benefits.

And I would also like for people to stop conflating what Javascript does with what JSX the DSL does, because some of the benefits mentioned are actually language-level feature requests in disguise.

Again this is not relevant.

What we really need from Google (Dart/Flutter) people is generic transpiling support via source maps so that any higher level language can be developed that targets Dart/Flutter and it would work just fine with the current tools (IDE, debugger, etc). Level the playing field and you guarantee the best ideas will come to the platform from others.

@filleduchaos

This comment has been minimized.

Copy link
Contributor

filleduchaos commented Dec 18, 2018

@cbazza

I am picking JSX syntax because it is well regarded in React and that's what React people expect and want. This ticket is about that, if that is not for you, don't use it.

That seems rather divisive and quite a bit entitled to me. Why should Flutter have first-class support for specifically React syntax? Why not Vue component files, or Xamarin.Forms syntax? Why must the (presumably official) UI DSL for Flutter be based on what one particular set of people using a different framework in a different language expect and want? If you want a community tool specifically for React/JS developers, that would be one thing. But asking for the framework itself to include it solely to cater to you all is a bit much IMO.

Whether it implements new semantics or not, it is irrelevant. Simplicity comes from its usage. If it is easy for users/developers to use, they will use it. Users/Developers don't care about how complex internally something is (or how much work it was to do), they just care how simple it makes their life and improves their code.

This is such a weird form of entitlement in my opinion. And no, developers will care about how complex an implementation is when it starts causing issues and feature drift as complexity in abstractions tends to do. Developers who want to do more than just use the DSL - extend it, for instance - will most definitely care about how complex the implementation is. The developers who would have to build and maintain it are also people that deserve consideration in this.

My intention with spread on DSX was just to spread attributes and not a complete JS implementation of spread. It works just fine for what it is and it has no type-safe issues at all. Type checking/correctness occurs when Dart compiles what DSX generates.

It only "has no type-safe issues" if you don't think about it at all. What I said was that Maps of arguments are not usable in a completely safe manner with the rest of a Dart codebase, where presumably you would want to interact with those arguments the way you can with props and such in JavaScript - pass them down from another Widget, import them from another module, etc - and not just declare them in one place, in which case what's the point over a normal constructor call?

To illustrate what I mean, you can do this in JS:

class MyCustomSize {
  constructor(length, width, height) {
    this.length = length;
    this.width = width;
    this.height = height;
    this.calculateVolume.bind(this);
  }

  calculateVolume() {
    return this.length * this.width * this.height;
  }
}

const Cuboid = ({ length, width, height }) => { // blah blah }

const literalSize = { 'length': 30, 'width': 20, 'height': 10 };
const size = new MyCustomSize(30, 20, 10);

size.length = 100; // Can interact with the object as normal, no compromises
console.log(size.getVolume()); // and even call methods
size.foo = 50 // If you're using TypeScript, you get a nice error
literalSize.height = 15 // can interact with the hashmap as though it were an object

const SomeComponent = () => (
  <div>
    <Cuboid {...literalSize} />{/* valid */}
    <Cuboid {...size} />{/* also valid even though size is an object */}
  </div>
)

But with Dart and your transpiler that requires hashmaps of arguments:

class MyCustomSize {
  int length, width, height;

  MyCustomSize(this.length, this.width, this.height);

  calculateVolume() {
    return length * width * height;
  }
}

class Cuboid extends StatelessWidget {
  final int length, width, height;

  Cuboid(this.length, this.width, this.height);

  @override
  Widget build(BuildContext context) { // blah }
}

Map literalSize = { 'length': 30, 'width': 20, 'height': 10 };
Map invalidSize = { 'length': 300, 'width': 200, 'height': 100 };
final size = MyCustomSize(30, 20, 10);

literalSize.height = 15; // Invalid, you must use square bracket notation which is honestly ugly to do a lot of the time
invalidSize['foo'] = 50; // No indication of anything wrong here

class SomeWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return (
      <Column>
        <Cuboid {...literalSize} />{/* Yes, works */}
        <Cuboid {...invalidSize} />{/* Sure the transpiled code errors as there is no parameter named foo. But this is now a completely opaque error. What if the `foo:50` key-value pair was added in some other section of your codebase? In a third party library even? How do you debug that*/}
        <Cuboid {...size} />{/* How do you plan on handling this as a plain transpilation step? */}
      </Column>
    )
  }
}

What cripped Dart in the early days was not providing simple JS interoperability so current JS libraries could be used easily with Dart code (and vice-versa). Also this is the exact same reason why Typescript succeeded where Dart failed.

Dart's interop with JS has never been complex, unless (and this is a point I keep stressing) you simply want to still write Javascript and are averse to learning anything else. Typescript being a superset does not so much have operability with JS as it simply is JS, to the point of deliberately having an unsound type system just to cater to JS (as well as no runtime to actually enforce its expressive type system, which is a damn shame this many years on). But back to my point, I personally feel Dart made quite a few poor design decisions for JS' sake and Dart 2 really should have been the first iteration of the language.

Popularity dictates everything. Best ideas are best ideas because they become popular because lots of people appreciate its benefits.

"Best", or rather good ideas are good ideas because they have merit. Sometimes they become popular, sometimes they don't. Sometimes bad ideas become popular, sometimes they don't. To suggest that popularity is a direct indicator of merit is frankly absurd and is an attitude I personally would very much rather not spill over into the Dart community, small as it is.

What we really need from Google (Dart/Flutter) people is generic transpiling support via source maps so that any higher level language can be developed that targets Dart/Flutter and it would work just fine with the current tools (IDE, debugger, etc). Level the playing field and you guarantee the best ideas will come to the platform from others.

...I didn't think it was possible to come of as even more entitled than you were before, and yet here we are. Why is it this one UI SDK that must be targetable by every high-level language on the globe? Once again the proposal strongly, strongly comes off as "Make Dart/Flutter into my language/framework" - you might as well just come right out and say you want to build Flutter apps with Javascript. And yeah, more grease to your elbow and I'd be all for contributing to a community project like that, but it's frankly ridiculous to expect a positive answer if you request official support for that.

Again reiterating - I don't mind a UI DSL and would actually love one. But if we're asking the team to bake it in then it should be a DSL that's idiomatic for Dart. Because yes, there are whole dozens of us out here who actually like Dart as a language.

Yet another edit: It would be one thing to request a DSL, suggest JSX as a possible syntax/syntax inspiration, and be open to other suggestions. It's the insistence on DSX that rubs me (and I suspect many who have commented) wrong.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Dec 18, 2018

@filleduchaos

You are hilariously confused and I don't have much time to waste yet.

The only thing I am asking of the Dart/Flutter team is what I said before:

What we really need from Google (Dart/Flutter) people is generic transpiling support via source maps so that any higher level language can be developed that targets Dart/Flutter and it would work just fine with the current tools (IDE, debugger, etc). Level the playing field and you guarantee the best ideas will come to the platform from others.

That provides everything necessary to implement DSX, Vue component files, Xamarin.Forms, NativeScript, QML, etc. and therefore would enable the community to come up with anything they want and nobody has to 'take' my DSX. Don't like DSX, you can use plain Dart or create your own thing with ease.

@rrousselGit

This comment has been minimized.

Copy link
Contributor

rrousselGit commented Dec 19, 2018

I'd say you're looking for things like https://github.com/dart-lang/build and dartanalyzer.
You'll likely miss a piece or two (like the ability to make analyzer plugins as pub dependency), but I'm pretty sure the Dart Team is fine with helping with that.

In any case, I don't think being harsh to each other continuously will help the framework progress in any way.
The most we'll get out of this is another permanently closed issue because it got "too heated".

@cbazza

This comment has been minimized.

Copy link

cbazza commented Dec 19, 2018

@filleduchaos

Regarding your 'foo' example, DSX spread is a compile time thing so map would need to be defined as const or I could come up with anything else I wanted to make that happens at compile time (for example create a new DSX keyword or annotation for it followed by the const map). It has to be at compile time, instead of at run time, because Dart doesn't support dynamic constructor parameter insertion at run time. Not a problem because it solve the problem I wanted to solve, i.e. spreading attributes on constructors.

@filleduchaos

This comment has been minimized.

Copy link
Contributor

filleduchaos commented Dec 20, 2018

@cbazza The point is that part of what makes the spread operator so handy in JS/JSX is that you don't have to impose restrictions like "you can only use a hashmap" or "all your arguments must be known at compile time" or "you can't interact with the arguments/props you want to pass to a Widget in the same way you can interact with everything else" (note that you haven't suggested anything to handle the case where the thing with the properties you need is actually an object, not a map literal) -0 it's all well and good when it's a simple example, but that sort of thing would get extremely frustrating fast in any medium-sized project. I mean, at what point does one stop piling on workarounds and compromises and annotations, take a step back and wonder if the extension is actually a good fit for the language as it exists?

JSX has been such a success (compared to most templates) because it doesn't force you to program a certain way (or rather, doesn't force you to write code any differently than you would have in Javascript anyway). It's pretty much completely painless to use with any JavaScript; this is what I mean by creating a DSL that actually fits the language. It's a similar thing with Redux. Redux in a JS codebase is a thing of beauty (when it's used properly); on the other hand all the Flutter examples I've seen using Redux extensively honestly just look painful compared to using Streams/the BLoC pattern. That's not to say that there aren't things that overlap with great success: React's Context and Flutter's InheritedWidget implement a common concept that caters incredibly well to the strengths of both. I'm just not convinced that JSX is currently one of those things - barring several language-level changes, it honestly looks like DSX would be a pain to develop and a pain to use for anything more than trivial examples, whereas one could probably write a feature-complete JSX transformer from scratch in a lazy weekend because of how straightforward it is to map to JS.

@filleduchaos

This comment has been minimized.

Copy link
Contributor

filleduchaos commented Dec 20, 2018

Also I was a bit aggressive earlier and I apologize.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Dec 20, 2018

@filleduchaos

I am not trying to create a fully generic spread operator that works everywhere and for everything, not even the one planned for future Dart is as generic as JS's one. What I want spread to handle in the context of DSX it does just fine. DSX has no need for spreading objects for example.

Spread Collections
dart-lang/language#47

I have developed super large projects with JSX and have really never needed to use spread on the tag attributes. JSX works great without it. The reason I added to DSX is because it solves a problem for Flutter widgets that there is no simple solution for it, specifically if a widget takes 20 parameters on the constructor how can you write that in less than 20 continuous lines that will make the widget tree a pyramid of doom. The only feature of DSX spread is to enable taking some of those lines out of the tree and place it somewhere else.

@sivabudh

This comment has been minimized.

Copy link

sivabudh commented Dec 22, 2018

@cbazaa I'm evaluating whether to use React Native or Flutter. Leaning towards Flutter because everything is just Dart so that the compiler can check my UI typos. Also see: https://medium.com/flutter-io/out-of-depth-with-flutter-f683c29305a8

Does JSX spot my typos as well? I use TypeScript.

I hate HTML / separate markups. For example, in Angular, if I mistyped something / variables in HTML, I only find my errors after rendering the page.

@cbazza

This comment has been minimized.

Copy link

cbazza commented Dec 22, 2018

@sivabudh

Does JSX spot my typos as well? I use TypeScript.

Yes, some JSX typos are caught at compile time (component name for example) but not prop names (which will be caught at run time) when using JS/ES6; but since you are using TypeScript the type system catches all JSX typos at compile time:
https://www.typescriptlang.org/docs/handbook/jsx.html

@pushqrdx

This comment has been minimized.

Copy link

pushqrdx commented Dec 30, 2018

@cbazza is dsx open source?

@cbazza

This comment has been minimized.

Copy link

cbazza commented Dec 30, 2018

@pushqrdx
Not yet, I have not released its source code.

@lukepighetti

This comment has been minimized.

Copy link

lukepighetti commented Jan 3, 2019

As a consumer of React + TypeScript and Flutter I can offer myself as a tester. Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment