Crystal -> JS Transpiler

I guess I should clarify that I consider the vanilla JS to be a catastrophe of a PL, but there are loads of wrappers around it already that have inherent properties making them “good”. I like CoffeeScript personally, but I’m not a full time FE dev.

Could we have a peek at your discussions regarding this?

It’s in a “Core Corner” private subforum. I don’t know why it’s private :frowning:

again hope you don’t mind the discussion, and thanks for explaining how you are looking at it.

JS bad - Coffee Script Better (agree here) - Ruby Much Better -> Crystal (guessing even better)

A single language for the entire system (and for us that includes not just FE, BE, but also desktop apps used in manufacturing) certainly makes life better, but that is probably the smallest reason for going to a single language.

The bigger reason is it greatly simplifies the overall application (measurable in LOC to get the job done.)

Here is an example of why: If you want to display some data from your model this all you have to do. looks pretty simple and easy to me anyway:

    class SearchResults < HyperComponent
      param :search_string
      UL do
        Shipment.matching(searching_string).each do |shipment|
          LI { ShipmentItem(shipment: shipment) }
        end
      end
    end

    class ShipmentItem < HyperComponent 
      param :shipment 
      DIV do
        DIV { "tracking no: #{shipment.tracking_id}" }
        UL do
          LI { "from: #{shipment.ship_from}" }
          LI { "to: #{shipment.ship_to}" }
        end
      end
    end 

This code will maintain the display dynamically as the database changes or as the search-string changes.

No extra code beyond that (and the ActiveModel definition of Shipment) is needed. No APIs, stores, reducers, etc, etc. This is the biggest savings, and its not just less code, its less room for error, since the you don’t have to remember to update both sides of the wire.

This is far, easier than any other solution out there, and after experimenting with Crystal, I think it becomes even better.

2 Likes

I think after semantic analysis is done…

And my understanding is at that point macros have all been expanded, type checking is complete, etc. Can I assume that everything is basically a method call on an object? If that question is too complex to answer then I will dive in and see what it all looks like.

Are there any tools for dumping / prettyprinting the AST ?

Thanks!

This is not Ruby though, this is a custom language. Ruby was designed in such a way that creating DSLs is not just easy, it’s natural. Crystal has a familiar syntax, but a completely different set of choices that in particular make DSLs much harder. What you need is not a transpiler from Crystal, you need an honest code generation toolchain that takes your custom DSL and writes all the actual code from it. This seems to me a nontrivial enterprise.

I would also like to point out that both Ruby and JS programs have ability to (re-)define themselves at runtime, whereas Crystal native ELFs have to be much more static. In your example the data types may be scraped off the database with all related decisions at any point, something you would lose if you migrate to Crystal. MVC model explicitely separates the data, the algorithms and the presentation, however your code suggests its tight integration, which is fine as long as you consider implications.

What I’m trying to say is with Ruby you don’t need code generation, because it’s done at runtime. With Crystal you have to recompile on each scheme migration, using either macros or some external tool to synchronize the data models between the database and the backend code.

I think this is a great idea, don’ t let nay-sayers stop you.

Why not try to go directly to the (i think) most promising wasm route?

3 Likes

I don’t feel that there are nay-sayers. It is just a different use case than the core team envisions. If some people have the skills to put together a JS transpiler, then I am sure the core team would rather get that energy focused on the main compiler work. I would probably feel the same.

Also I suspect people have not tried out isomorphic coding (like we do with https://hyperstack.org and ruby) and until you see it in action it is a “too good to be true story”.

Regarding WASM… the Opal transpiler goes to JS, and so that is a known and working use case. I would worry about these issues with WASM:

  1. debugging
  2. interoperating with JS code
  3. interoperating with the DOM

All these are fixable, but I think it would add a lot of work. Sure with WASM you could probably get up and running quicker, but you would be on a desert island until the above issues were solved.

Going to JS immediately fixes these issues.

If you have not played with https://hyperstack.org you should, and you will see what I mean.

I could be wrong about all of the above, but that is where I am coming from.

Cheers!

1 Like

Personally I believe I understand your position (generate everything from a single description), and I don’t really have anything against it, although this is not something I would choose for myself.

I just don’t think it’s gonna work well with Crystal is all.

This could be cool. Lots of work to do, but could definitely be awesome.

It is quite possible to have a usable and fun HTML DSL in Crystal. We do that in Lucky: https://luckyframework.org/guides/frontend/rendering-html#creating-a-page

Being able to mix in some JS with these templates could be pretty cool!

1 Like

@paulcsmith the lucky framework looks great. To be clear the big deal is the be able to execute on the client, so that you can dynamically update the DOM. The goal is never to have to write in JS, just be able to interoperate with existing JS libraries.

Whereas lucky right now can only generate the initial HTML, having crystal then running on the client it could update the HTML (ala React).

1 Like

Yeah totally! I was just thinking that a DSL similar to Lucky HTML could be used along side the Crystal-to-JS to make it super easy to write single page apps.

I was responding to a couple people unsure of what a Crystal JS DSL would look like. I personally think it could look pretty awesome!

3 Likes

Agreed! Like Lucky, Hyperstack has a complete templating DSL (in Ruby) that generates the initial HTML, and then also interoperates with React.

Crystal (via macros) would clean up the DSL. For example in Lucky I see you have this: needs user_names : Array(String) The equivalent in Hyperstack is param :user_name, type: [String] which is not as clean as Luckies syntax.

Also I am curious if the DSL tags (like ul, li) etc are macros, or methods? I have a hope that they could be implemented as macros, as all the translation to the underlying HTML (or in the case of React underlying React primitives) could be done at compile time.

1 Like

The underlying implementation does not use macros, which makes them much more flexible and easier to debug. The only macro we have is for generating the methods so we don’t have to do it by hand. The basics of the implementation can be found here: https://github.com/luckyframework/lucky/blob/4a2a528388b4ae3a229715dbc48f0a98ca7a5882/src/lucky/tags/base_tags.cr#L8

It generates various methods for each tag. Such as one that accept blocks, content, strings, etc.

1 Like

Crystal → JS is just one part of the problem. Then you need to bind to the DOM and all of the browser API.

Most of web apps are UI apps. React.JS and similar frameworks - abstract DOM away almost completely. Working with React.JS I forgot when was the last time I need to use Browser DOM API explicitly. So you can go very far and cover most web use cases by providing only React-like framework without full JS interoperability and without DOM API.

And it would also allow crystal to build cross-platform UI via Electron.

P.S. For the practical reasons - currently I guess TypeScript is the best opinion.

1 Like

Electron in 2019 lul

For practical and type safety reasons, I think Elm is the best option. I really suggest people play more with this wonderful language. It’s different (functional) but it’s so simple to get things done and to grow your app over time.

Speaking of functional languages… I tried Elixir and other functional languages but my mind can never wrap my head around them.

I think the only way I could learn is if I see code examples from the languages I already know, and how they are created in a functional way.

For example, take:

class Player
	property name = "Default Player #1"
	def initialize
    	pp self.name, " was created!"
	end
end

p = Player.new

No idea how this would be created in a functional language. I have read Elixir is used by some AAA game companies for servers, which is really cool.

…and I don’t even want to get into parameters and how they are passed. Reference or Value? Depends on the type? If allocated on heap vs stack?

In case you’re not set on browser environments only, native might be another option:
-> Is this a road to some crystal-to-all-platforms rails?