clojure-emacs / parseedn

EDN parser for Emacs Lisp
58 stars 14 forks source link

Printing dotted pairs fails in various ways #3

Closed jackrusher closed 4 years ago

jackrusher commented 4 years ago

If the second half is a string, it's converted into a series of integers representing character values:

(parseedn-print '(1 . "hi"))
(1 104 105)

If the second half is a number or t, emacs raises (wrong-type-argument sequencep 1):

(parseedn-print '(1 . 1))
(parseedn-print '(bin . t))

... and so on.

I'm guessing this never came up because the parser side of parseedn never produces association lists, but rather hash tables. I thought to fix the bug and submit a patch, but I'm currently unclear as to what transformation you would prefer in this case. :)

plexus commented 4 years ago

I'm not sure either :) whatever makes it work? A patch would be very welcome!

plexus commented 4 years ago

After a night of sleep my brain has woken up and realized what the actual issue is here. Clojure doesn't have dotted pairs :D (or more accurately, it doesn't have cons cells where the cdr is not a seq).

So in a way this behavior is defensible, as in "we can't do that, so we blow up". But that is of course not particularly helpful.

So what options do we have?

Introduce a reader conditional (lawful neutral)

#parseedn/cons [1 "hi"]

This is in a way the correct thing to do, we're faced with a data type that is not native to Clojure, so we mark it and leave it to the consumer to parse that to something meaningful. Pros: it's clear and it round trips, cons: it puts an extra burden on consumers.

Use a list with a dot symbol (lawful evil)

'(1 . "hi")

Pros: looks the same, can round trip (kinda). Cons: it's seriously going to confuse people.

Emit a two element vector (neutral good)

[1 "hi"]

A cons cell like this is basically a tuple, and if the idiomatic Clojure representation for that would be a two element vector. Note also the resemblance with a MapEntry.

Emit a map (chaotic neutral)

You could emit the cons cell as a map with a single entry, or even go a step further, assume the wrapping list is a association list, and emit that as a map.

This would rely on heuristics which would make it rather unpredictable what output you're going to get, just mentioning this since if you are outputting alists this would perhaps be conceptually closest to the semantics you're after.

Make it pluggable (True neutral)

Perhaps we just need to add an optional "dotted-pair-printer" argument and leave it to the user.

@jackrusher I don't have particularly strong opions on this one, and it seems so far no one else has run into this. How about we just pick the option that is most suitable for your use case?

jackrusher commented 4 years ago

I have an idea for an approach using a similar heuristic to the what the emacs JSON parser/printer uses that I'll experiment with soon! :)

plexus commented 4 years ago

Fixed by #4.