Thanks for all the thoughts on the language!  My responses:

On 3/17/21 6:36 PM, Joachim Breitner wrote:
I got “Some constructor unification variables are undetermined in
declaration” for unification variables in unused code (e.g. when I
stopped using some temporary recursive helper function). Made me wonder
if undetermined variables could be maybe be allowed in unused code, so
that I don’t have to comment out that code?
Maybe, but that's not as simple of an idea as it would be in classic Hindley-Milner type inference.  The reason is that, in general, not all values of remaining unification variables are legal.  There are other lingering constraints, including disjointness of rows, so it really would involve adding a somewhat-interesting solver.
In terms of developer usability, I was kinda expecting a “urweb watch”
mode that, upon changes to the sources, recompiles, restarts the
server, and maybe reloads the client. But not a big deal, I am just
spoiled.
I sometimes use my own simple external scripting to that end (watching the file system for changes), for interactive demos. However, for better or worse, large projects will take long enough to compile that I would think an unpleasant user experience could follow from automatic recompilation.
On the server side, the old app didn’t need any persistent state (it
only associated state with open connections), but in Ur/Web I had to
use the database to communicate between the open connections.
Yeah, it makes sense that that use case would require a bit of arbitrary-feeling setup, to use the SQL database for cross-HTTP-request state.  It's not at all the kind of scenario I had in mind in designing the language.  However, it would be easy enough to wrap all use of SQL in a functor exporting a pretty natural interface.
The “serialized” type
constructor was a bit odd; I wonder why can’t I just use the type
directly and instead have to serialize/deserialize, but I kinda see the
point.
I'm trying to remember why I introduced that type family years ago! Part of it is that I wanted to use type classes to control which types are allowed in SQL code values, so that functors may declare their expectations appropriately.  Serialization fails at compile time when used on inappropriate types, and that failure logic uses arbitrary compiler code, not a nice set of type-class instances.  So it can be seen as kind of a trick to get arbitrary type-level approval code into a type-class instance.
Ur/Web doesn’t support canvas drawing out of the box, but I found
https://github.com/fabriceleal/urweb-canvas/. Using a library like that
was simple enough. Unfortunately, it didn’t cover the full Canvas API
yet, and it seemed that adding the missing functions would require more
boiler plate than I wanted to write right now.

I can see how that makes sense for a quick pilot to evaluate the language, though I expect it's pretty cost-effective to extend that library with general Canvas features, for any kind of production app (and then everyone else gets to benefit from the improvements!).

In my experience, wrapping JavaScript libraries isn't a significant effort bottleneck for real projects, but you've raised a number of good ideas for improving the FFI experience, which I would at least be glad to see come in as pull requests, after some discussion on this mailing list.

But maybe the need to import JS libraries is just rare enough.
Speaking only for myself, there have been precious few JavaScript libraries that I've ever wanted to connect to from Ur/Web.  I think the tally stands at about five since 2006.  I find that most libraries used in web programming are making up for design mistakes in other libraries, Ponzi-scheme style.
Obviously, I need to connect the above function to a source/signal with
the game state. I found that this works, although I wonder if this is
an idiomatic way to do so:

           <canvas id={canvas_id} align="center" width=500 height=400/>
           <dyn signal={
             ui <- signal ui_state;
             return <xml><active code={
               drawDisplayState canvas_id (displayState ui);
               return <xml></xml>
             }/></xml>
The idiomatic way would be to use the features of the FFI for adding change listeners on signals.  You may have been thrown off by the fact that the library you took as inspiration does no such thing! You'll find JavaScript function "listen" documented briefly on page 59 of the currently posted reference manual.
I found it odd that I cannot have mutually recursive values of type
transaction (which is a function of sorts), and have to add unit
arguments. Probably a ML programmer finds that restriction natural,
with my Haskell background it was odd.
Right: Ur/Web has eager evaluation, so it is not coherent to allow recursive definition of just anything!  And it's an interesting question how such a language can allow introduction of new classes of recursive things in libraries, rather than as built-in language features.  Nothing about transactions is built into the Ur/Web core language.
Similarly, at one point I tried to use `s : source xbody <- source …`
for the main views (because why introduce a data type when there is
only a single function from that data type?). But that ran afoul a
similar problem, as … may not refer to `s`. Again, I was probably
thinking too Haskelly.

That example is actually easy to patch: initialize `s` with dummy code, then overwrite it with the new content, which may mention `s`.  (The only word of warning here is that the overwrite must happen in client-side code.)

However, I also think of the type `source xbody` as a bad code smell.  It is usually better to put your fundamental data model in sources and then derive HTML from them using <dyn> tags.

No derivation of show, soo useful for debugging and prototyping?
Not even for eq?
That would be great to see someone add!  You can actually get pretty good generic printing using conversion to JSON already, though.
I missed a less heavy variant `let`. Especially one that lines up
nicely with do notation (`let val x = y in e end` is a mouthful, and
adds indentation). I resorted to `x <- return y; e`, not sure how bad
that is.
I tried to add a lighter-weight version way back when, and I ran into some aggravating conflict in the parser generator.  Yes, the version with `return` is what I write myself these days.  I'd love to see a patch adding a lighter-weight version that doesn't break other notations!
No eq for tuples predie
There is a generic implementation in UPO <https://github.com/urweb/upo/blob/master/record.urs>. (It's important to keep in mind that tuples are a special case of records in Ur/Web.)
Irrefutable patterns in `p <- e; e` are useful, and I missed them also
in `fn p => …`, especially when working with association lists.
Actually, irrefutable patterns /do/ work with anonymous functions!  Something else must have gone wrong to throw you off. Maybe your example was missing parentheses around the pattern.
The CSS parser didn’t like some property names I was using:
“Invalid string -webkit-hyphens passed to 'property'”
Ah, sounds like I should just change the function that validates property names.  The implementations in SML <https://github.com/urweb/urweb/blob/master/src/mono_opt.sml#L186> and JavaScript <https://github.com/urweb/urweb/blob/master/lib/js/urweb.js#L3379> both force property names to start with letters or underscores.  Is it clear that hyphens should be allowed as well, with no further restrictions?
Similarly, and just like almost any statically typed view on HTML,
there are always tags and properties missing. In my case, tabIndex. No
big deal, just minor friction.
I'll be happy to take a pull request adding an innocuous-sounding feature like that one.
At some point I briefly used variants, but the syntax was a bit
verbose, and they didn’t add anything of value over data types at that
point. But later I think I could have done fun fancy generic stuff with
them if I had them. Still makes me wonder if we can’t simply have both
(e.g. variants everywhere).  Is it that type inference suffers too
much?
I would like to see algebraic datatypes and polymorphic variants unified in a complete rewrite of Ur/Web some day.  For now, variants are really only worth using in connection with metaprogramming.  I have almost never written code with a variant of known type.
Urweb generates data base schemas to create databases. But it seems the
problem of migrating existing data from prior versions to the schema of
new versions does not get any built-in help in Ur/Web. Ideally somehow
Ur/Web allows me to specify (declaratively or by code) how to migrate
from old versions, and I get the end-to-end static typing support that
I came to Ur/Web for. But it’s obviously a hard problem, and discussed
before (e.g. at https://github.com/urweb/urweb/issues/65). Still, I
wonder how production users of Ur/Web deal with this?
I write my own migrations outside Ur/Web.  It's typically fairly easy with SQL schema-manipulation commands.  I also agree it would be nice to have a generic solution in the language tooling; all the relevant information is already kept, with the main complication being how to make it possible to talk about old versions of a schema.  That could actually get pretty involved, what with Ur/Web's commitment to allowing modules to have private tables.  IMO, it would be an antipattern to force consideration of an application's database schema as a monolithic, flat definition.  I also use apgdiff <https://github.com/fordfrog/apgdiff> sometimes for the dumbest possible automatic schema adaptation, and it usually works.
It seems that Ur/Web projects are so nicely self-contained, they should
be ideal candidates for serverless deployment. I guess one can’t easily
use Amazon Lambda, because the server is actually stateful (to persist
these client connections), but I could still imagine that some auto-
deploy-from-github-repo-without-configuration (like netlify etc.
offer), including data base etc. might be a nice add-on at some point,
so that it takes just minutes from writing your foo.urp to having a
live site.
Agreed!  I'd love to see a pull request with that kind of scripting, even included in the main project repo (though I believe it should be quite doable with minimal code from an unprivileged position).
I imagine if I didn’t have to deal with Canvas,
I agree it's fair to point out lack of an existing library for a standard HTML feature was a fundamental obstacle, but...
and maybe went for something less AJAXy and more
classical web programming with links and POSTs,
...here I have to disagree.  I'll continue claiming that Ur/Web supports AJAXy programming better than anything else out there!  I don't put many links or old-school forms in Ur/Web applications I write these days.  (However, many web API requests use POSTs today, so I'm not sure what that part of your characterization is meant to draw attention to.)
_______________________________________________
Ur mailing list
Ur@impredicative.com
http://www.impredicative.com/cgi-bin/mailman/listinfo/ur

Reply via email to