Slowly climbing up the Elm learning curve, I made it crash runtime yesterday, and I just wanted to report to the mailing list. This may be a known issue, but as a novice I'm making all kinds of rookie mistakes. As such, when those rookie mistakes cause a runtime crash without a compiler complaint, I'll try to report them here.
The short version: You can do this in Elm:
> v = v+1
NaN : number
I would have expected that to crash, because v is being used before it is defined.
In the clojurescript repl, I get a similar case:
cljs.user=> v
WARNING: Use of undeclared Var cljs.user/v at line 1 <cljs repl>
nil
cljs.user=> (def v (+ v 1))
#'cljs.user/v
cljs.user=> v
NaN
But in the clojure repl (Java based, not JavaScript), I get the crash I was looking for.
boot.user=> (def v (+ v 1))
clojure.lang.Compiler$CompilerException:
java.lang.ClassCastException: clojure.lang.Var$Unbound cannot be cast
to java.lang.Number, compiling:(boot.user7277212806697690427.clj:1:8)
java.lang.ClassCastException: clojure.lang.Var$Unbound cannot be cast to java.lang.Number
I suspect this will always be the case, but it led to a runtime crash, as explain in the longish writeup below
Background, I want a date picker element in my page, so I copied in the elm-datepicker (
https://github.com/Bogdanp/elm-datepicker). In copying I omitted something I thought was small, which in turn caused my program to pass compiling but crash runtime.
The code snippet from the real example that broke relates to the "update" behavior. The original says:
```
update : Msg -> Model -> ( Model, Cmd Msg )
update msg ({ datePicker } as model) =
case msg of
ToDatePicker msg ->
let
( datePicker, datePickerFx, mDate ) =
DatePicker.update msg datePicker
...
```
Note the construct `({datePicker} as model)` As a newcomer, that is something I've never seen before. Not something that is documented on the "syntax" page (
http://elm-lang.org/docs/syntax), and not something I can find in the get started guide.
https://guide.elm-lang.org/get_started.html I *guessed* that it was some sort of way to desctructure the incoming model argument, but because I had many cases, I didn't want to bother with that for just this one case.
(Better docs would probably have helped my understanding, but this is young language...if I just wanted better docs, I'd still be using JavaScript)
Anyway, I dropped the destructuring thing, whatever it is. My version looked like:
```
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
ToDatePicker rec ->
let
( datePicker, datePickerFx, mDate ) =
DatePicker.update rec datePicker -- <== bug here!
...
```
I changed the incoming destructuring thing, and I swapped out the nested redefinition of "msg" for "rec", but I *forgot* to say "model.datePicker" inside the let statement.
Strangely, this compiles just fine. I would have expected to see at least a warning, because the rhs of the assignment is using a variable that is first declared on the lhs of the assignment. Actually, no. That's too weak. I expect the compiler to bomb out in such a case.
But it doesn't
```
=================================== WARNINGS ===================================
-- unused import - /home/james/repos/jem/calvad/calvad_ui/elm-calvadui/src/elm/Main.elm
Module `Date.Extra.Format` is unused.
15| import Date.Extra.Format as Format exposing (format, isoDateFormat,formatUtc, isoStringNoOffset)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Best to remove it. Don't save code quality for later!
Success! Compiled 1 module.
Successfully generated /tmp/116830-14831-1hiiwmv.2po3kdquxr.js
```
(The warning that *is* there relates to an unused module, not to the usage of an undeclared variable.)
Running that, I see the following runtime crash:
```
TypeError: _p23 is undefined
_Bogdanp$elm_datepicker$DatePicker$update<() c4836e16ec49f9b909df.js:35001
A2() c4836e16ec49f9b909df.js:25776
_jmarca$elm_calvadui$Main$update<() c4836e16ec49f9b909df.js:37131
... blah blah blah ...
```
Of course it crashes, because datePicker is undefined when DatePicker.update is called on it. Once I spotted the error the fix was easy, but it took probably 2 hours for me to spot it.
My guess is that using undefined variables that get auto-defined-and-hoisted will always be a problem because this is JavaScript under the hood. This also affects clojurescript apparently, as is shown by my tl;dr up above. Only clojure/java crash properly when using undefined variables.
Regards,
James