Skip to content

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

Merged
merged 6 commits into from
Feb 8, 2017
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Jan 31, 2017

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 ?

Copy link
Contributor

@OlivierBlanvillain OlivierBlanvillain left a 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)

dotty-staging@dc4f84e

"Failed Implicit"
case result: AmbiguousImplicits =>
"Ambiguous Implicit: " ~ toText(result.alt1) ~ " and " ~ toText(result.alt2)
case _ =>
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like we can

Copy link
Contributor Author

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.

@odersky
Copy link
Contributor Author

odersky commented Feb 2, 2017

Some current advantages of enum as a syntax:

  • Less verbose syntax
  • Gives us a robust way to find all children of a class. Even using sealed we still have problems with that because exploration can cause cycles.
  • Gives us an efficient way to create enums with many values.
  • Opens the potential to represent some enums as Java enums, which helps interop
  • Give us a lightweight way to hide implementation classes. E.g. We'd like Cons, Nil to be
    of type List (instead of a subtype) because this helps sometimes with type inference.

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]
Copy link
Member

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?

@odersky odersky force-pushed the fix-implicits-generic branch from f3145f2 to 2ce9328 Compare February 3, 2017 05:04
@xeno-by
Copy link

xeno-by commented Feb 4, 2017

@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")
Copy link

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)
}
Copy link

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
Copy link

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
Copy link

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
Copy link

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) {}
}
Copy link

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?

Copy link

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?

Copy link
Contributor Author

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] {
Copy link

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?

Copy link
Contributor Author

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.
@odersky odersky force-pushed the fix-implicits-generic branch from 2ce9328 to 56d32fa Compare February 8, 2017 08:36
@odersky odersky merged commit b77c24c into scala:master Feb 8, 2017
@allanrenucci allanrenucci deleted the fix-implicits-generic branch December 14, 2017 19:20
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.

4 participants