-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Remove implicit conversion from liftable types to Expr[T] #4129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove implicit conversion from liftable types to Expr[T] #4129
Conversation
Use `import scala.quotes.Liftable._` and `x.toExpr` notation instead.
To use `import scala.quotes._` to import `toExpr` extension
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the reason for dropping the conversion? I'm asking because MetaML supports lifting without conversions out of the box.
In general, it has proven to be awkward to have these implicit transformations. By looking at the code it is not always simple to know what is lifted and what is not. Which seems to make it harder to see the different stages in the code. If we require an explicit @OlivierBlanvillain might have some additional reasons. |
Maybe a case to introduce an @implicitNotFound annotation on implicit conversions? |
I am not convinced yet that this is a good idea. |
Currently, we can automatically lift with the implicit conversion
We can also explicitly lift using
There is also the corner case where a value is lifted but not used in a splice
But we cannot lift
This last version would be the only way to lift if this PR in merged. Which is shorter and clearer than using implicit conversion in most cases (see first code example and compare with second). I saw this while coding https://github.com/nicolasstucki/quoted-util, specifically this commit . implicit def Tuple22IsLiftable[T1 : Liftable : Type, T2 : Liftable : Type, T3 : Liftable : Type, T4 : Liftable : Type, T5 : Liftable : Type, T6 : Liftable : Type, T7 : Liftable : Type, T8 : Liftable : Type, T9 : Liftable : Type, T10 : Liftable : Type, T11 : Liftable : Type, T12 : Liftable : Type, T13 : Liftable : Type, T14 : Liftable : Type, T15 : Liftable : Type, T16 : Liftable : Type, T17 : Liftable : Type, T18 : Liftable : Type, T19 : Liftable : Type, T20 : Liftable : Type, T21 : Liftable : Type, T22 : Liftable : Type]: Liftable[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22)] = {
- x => '{ (~(x._1: Expr[T1]), ~(x._2: Expr[T2]), ~(x._3: Expr[T3]), ~(x._4: Expr[T4]), ~(x._5: Expr[T5]), ~(x._6: Expr[T6]), ~(x._7: Expr[T7]), ~(x._8: Expr[T8]), ~(x._9: Expr[T9]), ~(x._10: Expr[T10]), ~(x._11: Expr[T11]), ~(x._12: Expr[T12]), ~(x._13: Expr[T13]), ~(x._14: Expr[T14]), ~(x._15: Expr[T15]), ~(x._16: Expr[T16]), ~(x._17: Expr[T17]), ~(x._18: Expr[T18]), ~(x._19: Expr[T19]), ~(x._20: Expr[T20]), ~(x._21:Expr[T21]), ~(x._22: Expr[T22])) }
+ x => '{ (~x._1.toExpr, ~x._2.toExpr, ~x._3.toExpr, ~x._4.toExpr, ~x._5.toExpr, ~x._6.toExpr, ~x._7.toExpr, ~x._8.toExpr, ~x._9.toExpr, ~x._10.toExpr, ~x._11.toExpr, ~x._12.toExpr, ~x._13.toExpr, ~x._14.toExpr, ~x._15.toExpr, ~x._16.toExpr, ~x._17.toExpr, ~x._18.toExpr, ~x._19.toExpr, ~x._20.toExpr, ~x._21.toExpr, ~x._22.toExpr) }
} |
With implicit conversions, we also can easily write buggy code without noticing. For example both of the following methods will typecheck, though there is a missing
This has already happened a few times to me. |
I am still not convinced. None of these seem to be serious problems for MetaML. Beware of expert syndrome here! Your initial users will have only a faint idea what goes wrong. If a simple and obvious thing does not work because it misses a "Make simple things easy and complex things possible" -- we should take that seriously. |
Then we should support automatic lifting for the case
This seams to be the most common case. Which might become a bit tricky with types that already define |
I don't think it makes things easier to blur the distinction between compilation time and execution time. The biggest obstacle when first trying out staging is to understand what happens at what stage. I believe having implicit conversion involved makes it significantly harder to get started with multi stage programs. Also, it's literally a one line addition in user code to revert what this PR does, simply define
That's because they don't have any automatic lifting it in metaocaml, everything has to be precisely annotated: let x : int code = .<1>.
-- compile ok let x : int code = 1
-- metaocaml test.ml
File "./test.ml", line 2, characters 21-22:
Error: This expression has type int but an expression was expected of type
int code
BER MetaOCaml toplevel, version N 104
Compilation exited abnormally with code 2 at Mon Mar 19 11:57:10 |
Use
import scala.quotes._
andx.toExpr
notation instead.