-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Improvements to implicits #1918
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
Conversation
e9d324e
to
2294e82
Compare
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 would be the motivation for an enum
syntax? If the goal is lighter syntax for sealed hierarchy of case classes, it looks like this would be a perfect use case for an @enum
annotation implemented using scala.Meta's syntactic APIs.
I think having a bijection between Scala types and a sum of product representation (the shaped
type class of this PR, or shapeless's Generic) should be enough in itself to get all the benefits of enums. For instance, if we also add a ValueOf
type class to obtain values associated to literal singleton types, we compute all the values of an enumeration via implicit resolution: (enumTag
can probably be computed in a similar way)
"Failed Implicit" | ||
case result: AmbiguousImplicits => | ||
"Ambiguous Implicit: " ~ toText(result.alt1) ~ " and " ~ toText(result.alt2) | ||
case _ => |
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.
Could we seal SearchResult
instead of having a default case?
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.
Looks like we can
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.
No, in fact we cannot. There are too many other cases we'd have to handle. E.g. ExplainedSearchResult. Sometimes it's better not to seal.
Some current advantages of
Could this be done with Scala meta? I doubt it since the natural enum syntax is not currently legal Scala. Also there's a "meta discussion" to be had about Scala meta. Language workbenches are very appealing academically but often turn to nightmares in practice. Google for "The Lisp Curse" for details. |
|
||
case class EnumValue[E](tag: Int) | ||
|
||
trait shaped[SH1, SH2] extends unfolds[SH1, SH2] |
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's the difference between shaped and unfolds?
f3145f2
to
2ce9328
Compare
@OlivierBlanvillain @odersky As defined in the examples, the syntax for enums cannot be implemented in scala.meta. In new-style macro annotations, we only accept annottees written using regular Scala syntax. At the moment, we don't have plans to turn scala.meta into a language workbench. The main goal of the project is to provide syntactic and semantic API for standard Scala to be used in developer tools and macros. |
if (owner.isTypeName && !(mods is Local)) | ||
syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name") | ||
else if (imods.hasFlags) | ||
syntaxError("implicit parameters may not be call-by-name") |
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.
Why was this prohibited in scalac?
def enumTag = tag | ||
override def toString = name | ||
registerEnumValue(this) | ||
} |
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.
Can we have a named subclass of Color
defined somewhere in the companion object and used here? I think that classnames of anonymous classes are quite ugly.
import Shapes.Singleton | ||
|
||
trait Enum { | ||
def enumTag: Int |
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 use cases do you envision for enumTag
? Back then, @densh and I planned to use tags to speed up pattern matching. Do you think that'd make sense?
def enumTag: Int | ||
} | ||
|
||
trait FiniteEnum extends Enum |
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's that?
private var myValues = new Array[AnyRef](numVals) | ||
|
||
def registerEnumValue(v: E) = | ||
myValues(v.enumTag) = v |
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.
Can we somehow restrict the visibility of this method?
new (Cons[T] `shaped` Prod[T, List0[T]]) { | ||
def toShape(x: Cons[T]) = Prod(x.hd, x.tl) | ||
def fromShape(p: Prod[T, List0[T]]) = new Cons(p.fst, p.snd) {} | ||
} |
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.
@odersky Am I right in thinking that you'd like the XXXShape
implicits to be derived by macros?
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.
And, in general, which parts of the enum
proposal do you see implementable as macros, and what you'd like to hardcode in the compiler?
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.
@xeno-by The XXXShape
implicits can be done by the compiler. The part I need from macros are the implicits in Test.scala.
} | ||
} | ||
|
||
/** enum List[T] { |
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.
Is the variance modifier omitted here on purpose?
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.
There are actually two sources, one without variance for List0, the other with variance for List1.
The previous condition for caching companionRefs contained a condition result.companionRefs.forall(implicitScopeCache.contains) which was always false because we cache types in `implicitCodeCache`, not companion refs. The new logic fixes this and does not need a second traversal because it is integrated in `iscopeRefs`.
When printing info about adding to constraints, show the hashes of the typerstate stack, so that we know where constraints are added.
The test exercises all the improvements made in previous commits of this branch.
2ce9328
to
56d32fa
Compare
The PR contains an optimization and a generalization of implicits
Optimization: We now avoid recomputation of companion refs in many cases
Generalization: We allow implicit call-by-name parameters
There are also some improvements to internal diagnostics regarding implicits.
There a largish test case, which explores some schemes for generic programming over ADTs.
Review by @smarter, @OlivierBlanvillain ?