convex icon indicating copy to clipboard operation
convex copied to clipboard

Settling on predictable and consistent coercions

Open helins opened this issue 4 years ago • 9 comments
trafficstars

The recent work done on avoiding unnecessary implicit casting in functions has provided a lot of clarity (eg. avoiding (+ \a true)).

However, the coercion functions themselves are not there yet in my opinion. Four things to consider :

  1. Ensuring consistency in errors. For example, this string cannot be used as a hexstring (odd length):
(address "123")

;; ARGUMENT: String not convertible to a valid Address: 123

(blob "123")

;; Cast error: Can't convert argument at position 1 (with type String) to type Blob.

;; Both should be either :ARGUMENT or :CAST
  1. Make a distinction between wrong type and wrong argument. I guess it would be best to keep the current (but inconsistent) distinction between :ARGUMENT and :CAST. That (blob "123") error is misleading because it looks like no string at all can be converted to a blob. Ideally there should be enough information attached so that the consumer can understand why. Programmatically, so that an environment like the sandbox can humanize it as needed.

  2. Avoid non-obvious double coercions. This is more of a opinion but those are examples of situations that looks a bit weird:

(char true)  ;; bool -> long -> char
(double \a) ;; char -> long -> double
  1. Allow double coercions when they look completely transparent. Especially in collections:
;; Given that the following works:
(vec {:a :b})
(vec 0x1234)

;; The following should work (but currently don't)
(set {:a :b})
(set 0x1234)

;; And should be consistent with `into` which should accept any `Countable`
(into [] 0x1234)  ;; Doesn't work, but looks like (vec 0x1234)

helins avatar May 27 '21 14:05 helins

Another example:

(blob-map "45" 45)

;; Cast error: Can't convert argument at position 1 (with type String) to type Blob.

(assoc (blob-map) "45" 45)

;; ARGUMENT: Cannot assoc value - invalid key of type String

helins avatar May 27 '21 18:05 helins

I've created a draft CAD for error handling: https://github.com/Convex-Dev/design/blob/main/cad/errors.md

CAD improvements and/or PRs to improve consistency welcome!

mikera avatar May 28 '21 03:05 mikera

(good stuff like I said :) )

And how do you feel about things like (char true) ?

helins avatar May 30 '21 16:05 helins

(char true) should die for sure! That's truly an abomination.

I think a single level explicit cast Number -> Something or Something -> Number is probably fine, but Something -> Number -> Something is probably wrong.

mikera avatar May 31 '21 10:05 mikera

Agreed, but honestly I even hesitate for stuff like (double \a) (Something -> Long -> Double).

helins avatar May 31 '21 19:05 helins

Can you think of a good way to visualise all the possible coercions? I am thinking of some sort of 2D table "Cast function <-> Type". Maybe we can build programmatically and eyeball the results.

mikera avatar May 31 '21 22:05 mikera

For scalar values, I guess that anything that can map to a number usually map to an integer, more precisely. Because those are usually finite sets of countable entities (booleans, chars, ...). So I would forbid any direct (double x) conversion but for actual numbers. If really want to end up with a double, do (double (long x)). It also implies the opposite, you cannot do (char 97.0) but must do (char (long 97.0)). This already simplifies quite a lot I find. You still have the freedom to do explicitly any crazy conversion that you heart desire and at least, you know what you are doing.

For real collections ('() [] {} #{}), I would expect conversion from any coll to any coll.

helins avatar Jun 02 '21 13:06 helins

More than a year later, I still reached the same conclusion. (char false) feels weird.

helins avatar Nov 05 '22 13:11 helins

I have tightened the char handling specifically. These coercions are a little complex because: CAST = wrong argument type provided ARGUMENT = type is potentially valid, but value didn't work (e.g. outside unicode range)

Logically, these are different things

mikera avatar Nov 08 '22 07:11 mikera