Skip to content

Deprecate old Expr value extractors #10684

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

Merged

Conversation

nicolasstucki
Copy link
Contributor

  • Now we use expr.value, expr.valueOrError, Expr.unapply and Exprs.unapply
  • We keep them to help migration between 3.0.0-M2 to 3.0.0-M3

* Now we use `expr.value`, `expr.valueOrError`, `Expr.unapply` and `Exprs.unapply`
* We keep them to help migration between 3.0.0-M2 to 3.0.0-M3
@nicolasstucki nicolasstucki added this to the 3.0.0-M3 milestone Dec 7, 2020
@nicolasstucki nicolasstucki linked an issue Dec 7, 2020 that may be closed by this pull request
@nicolasstucki
Copy link
Contributor Author

We also have a copy of these extractors in https://github.com/nicolasstucki/quoted-util/tree/master/src/main/scala/quoted/util. We can consider adding them back after 3.0.0 if we see that is actually useful.

@@ -1,6 +1,7 @@
package scala.quoted

/** Literal constant values */
@deprecated("Use `scala.quoted.Expr` instead. This will be removed in 3.0.0-RC1", "3.0.0-M3")
object Const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember in the meeting we agree to keep Const as an extractor. Or I misunderstood?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We keep it in scala.quoted.util as it duplicates logic in scala.quoted. This is the only responsable action as we could add it back in scala.quoted but we would not be able to remove it.

It is already in scala.quoted.util.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be a pity that when a meta-programmer wants to pattern macher on a constant (which is a common need as we know in meta-programming), he has to add another library as a dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is that they can do it using .value or Expr. Both cover all the cases that Const covers without the performance penalty and with better warnings in the pattern matching. It would be a pity to give them a version that is just tempting to use due to its name, but is always a worse option.

We have already seen that all uses cases in our test and in the community-build where better with .value/Expr. We do not have any remaining places were we would use Const.

Explaining this extractor to new users is also unnecessarily hard and confusing. After introducing .value/Expr we need to tell them that they can optionally use this other variant that does less and is less performant. Why would a user want to use it then? Then the next step is to tell them that the Const extractor does not match Constant, the reason being that Const matches what Expr matches but only for primitive types. This amount of confusion is too much. I know what is the difference between those extractors, but even you, having worked with them for a long time, have show confusion about the differences.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have already seen that all uses cases in our test and in the community-build where better with .value/Expr. We do not have any remaining places were we would use Const.

I basically agree with this. However, we cannot exclude some use cases where the usage of Const(v) in pattern matching is more convenient. If I were correct, the typical textbook example power is one such usage.

On the other hand, something is missing at the conceptual level if there is no capability to directly pattern match on literals, while it is possible to do so on other syntactic forms. If we remove this capability, it would be good to remove pattern matching on quotes completely, and only keep tree pattern matching in reflect, which IMHO is a reasonable choice.

Explaining this extractor to new users is also unnecessarily hard and confusing.

It seems to me in meta-programming, inspecting literals is very natural, and having a dedicated extractor for that will not cause problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the following power?

def power(xExpr: Expr[Double], nExpr: Expr[Int])(using Quotes): Expr[Double] =
  (xExpr.value, nExpr.value) match 
     case (Some(x), Some(n)) => Expr(x.pow(n))
     case (Some(x), _) => '{...}
     case (_, Some(n)) => unrollPower(xExpr, n)
     case (_, _) => '{ $xExpr.pow($nExpr) }

How would that benefit from using Const or Expr? We could do the following but it only has drawbacks. Calling Const.unapply is more expensive than .value and we need to call it twice instead of once.

-  (xExpr, nExpr) match 
-    case (Const(x), Const(n)) => Expr(x.pow(n))
-     case (Const(x), _) => '{...}
-     case (_, Const(n)) => unrollPower(xExpr, n)
-     case (_, _) => '{ $xExpr.pow($nExpr) }

It seems to me in meta-programming, inspecting literals is very natural, and having a dedicated extractor for that will not cause problems.

We have a dedicated concept for it which is called FromExpr and used by Expr.unapply. Calling it Const or Literal only leads to confusion as those do not match Constants or Literals. They match what Expr matches. It does not make any sense overload concepts and bloat the API with duplicated logic. It is simpler to explain Expr and be done with it rather than giving them another option that does less but requires the understanding the Expr first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the following power?

def power(xExpr: Expr[Double], nExpr: Expr[Int])(using Quotes): Expr[Double] =
  (xExpr.value, nExpr.value) match 
     case (Some(x), Some(n)) => Expr(x.pow(n))
     case (Some(x), _) => '{...}
     case (_, Some(n)) => unrollPower(xExpr, n)
     case (_, _) => '{ $xExpr.pow($nExpr) }

How would that benefit from using Const or Expr? We could do the following but it only has drawbacks. Calling Const.unapply is more expensive than .value and we need to call it twice instead of once.

-  (xExpr, nExpr) match 
-    case (Const(x), Const(n)) => Expr(x.pow(n))
-     case (Const(x), _) => '{...}
-     case (_, Const(n)) => unrollPower(xExpr, n)
-     case (_, _) => '{ $xExpr.pow($nExpr) }

Thanks for correcting my memory. I have in mind use cases like case '{ power(${const(x)}. $y) } => ..., where the usage of extractors are more convenient than .value.

It seems to me in meta-programming, inspecting literals is very natural, and having a dedicated extractor for that will not cause problems.

We have a dedicated concept for it which is called FromExpr and used by Expr.unapply. Calling it Const or Literal only leads to confusion as those do not match Constants or Literals. They match what Expr matches. It does not make any sense overload concepts and bloat the API with duplicated logic. It is simpler to explain Expr and be done with it rather than giving them another option that does less but requires the understanding the Expr first.

It seems to be the exact reason why it cannot be renamed --- because Expr.unapply is not dedicated for pattern matching on literals. Missing a dedicated extractor for a category of syntactic forms seems to be a flaw at the coneptual level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be renamed as shown in #10673. But there was some backlash against that. Either way, we cannot add every of the extractor in the library. This is why scala.quoted.util was created. This way we can provide different more specialized extractors such as Const, Value, StringContextExpr, ... . All those extractors that are not required or not necessarily practical to all users.

I cannot spend more days fixing this issue. We should just merge it. Users will be able to use trivially the scala.quoted.util.Const instead or other variants that we might come up with that is more inline with their goals. If in the future we see actual use cases, then we can consider moving it to scala.quoted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be arguments for the design I'm not aware of. Please do what makes sense.

@nicolasstucki
Copy link
Contributor Author

nicolasstucki commented Dec 8, 2020

This extractor should have been removed when we introduced the proper FromExpr based extractor and first saw that it was redundant. I only kept it because this way I would not need to change some tests, which ended up happening anyway as it was always worse to use Const.

I firmly believe that the library and users should not have to suffer because I was lazy back in some older PR.

Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nicolasstucki nicolasstucki merged commit a1434a8 into scala:master Dec 8, 2020
@nicolasstucki nicolasstucki deleted the depricate-old-Const-extractor branch December 8, 2020 14:04
@Kordyjan Kordyjan modified the milestones: 3.0.0-M3, 3.0.0 Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Remove scala.quoted.{Const, Consts}
3 participants