Skip to content

Insert traits with implicit parameters as extra parents of classes #11830

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 4 commits into from
Mar 23, 2021

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Mar 21, 2021

If a trait A extends some other trait B which takes an implicit parameter, and
a class C extends A but not B, we need to insert B into the parents of C, so
that the implicit argument can be generated.

This required a generalization of the syncing between parent trees and parent types.
Namer will augment the parent types of a class with possibly other types.
Previously the only such change was a possibly leading class type, but we now
also generate trait parents that take context parameters. The new method parentTrees
reflects any such changes in the parent trees in Typer.

Fixes #7613

If a trait A extends some other trait B which takes an implicit parameter, and
a class C extends A but not B, we need to insert B into the parents of A, so
that the implicit argument can be generated.

This required a generalization of the syncing between parent trees and parent types.
Namer will augment the parent types of a class with possibly other types.
Previously the only such change was a possibly leading class type, but we now
also generate trait parents that take context parameters. The new method parentTrees
reflects any such changes in the parent trees in Typer.
@odersky odersky changed the title Generalize syncing between parent trees and parent types Insert traits with implicit parameters as extra parents of classes Mar 21, 2021
@odersky odersky requested a review from smarter March 21, 2021 17:28
@odersky odersky self-assigned this Mar 21, 2021
@smarter
Copy link
Member

smarter commented Mar 21, 2021

Nice! Would you mind documenting this in http://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html ?

@odersky odersky assigned smarter and unassigned odersky Mar 21, 2021
@odersky odersky added this to the 3.0.0-RC2 milestone Mar 22, 2021
@therealcisse
Copy link
Contributor

Will the following code work as a result of this change ?

trait Semigroup[A]:
  extension (a: A) def combine(b: A): A

trait Monoid[A: Semigroup]:
  def unit: A

given Semigroup[Int] with
  extension (a: Int) def combine(b: Int): Int = a + b

given Monoid[Int] with
  def unit: Int = 0

def sumList[A: Monoid](ls: List[A]): A = ls.foldLeft(summon[Monoid[A]].unit)(_.combine(_))

@main def Test() = 
  val ls = List(1,2,3)
  println(sumList(ls))
   

@odersky
Copy link
Contributor Author

odersky commented Mar 23, 2021

@amsayk The change would help, but your example does not compile since combine is not defined on Monoid.

@therealcisse
Copy link
Contributor

therealcisse commented Mar 23, 2021

Yeah that makes sense. Maybe an export would help to fix that then.

trait Semigroup[A]:
  extension (a: A) def combine(b: A): A

trait Monoid[A](using S: Semigroup[A]):
  export S.combine
  def unit: A

given Semigroup[Int] with
  extension (a: Int) def combine(b: Int): Int = a + b

given Monoid[Int] with
  def unit: Int = 0

def sumList[A: Monoid](ls: List[A]): A = ls.foldLeft(summon[Monoid[A]].unit)(_.combine(_))

@main def Test() = 
  val ls = List(1,2,3)
  println(sumList(ls))

I think this example showcases the line between OOP inheritance and addhoc polymorphism. One would intuitively think that since A is a Monoid, it is also a Semigroup (because a given of Semigroup exists) and thus should have the combine method.

@therealcisse
Copy link
Contributor

therealcisse commented Mar 23, 2021

On a somewhat related note, I want to ask:

The above code uses the syntax _.combine(_) because the extension method was desugared using two parameter groups. This syntax looks a little overloaded to be especially now that Scala is trying to reduces use cases for the underscore.

If extension methods with desugared to a single parameter group, we could simple write:

  def sumList[A: Monoid](ls: List[A]): A = ls.foldLeft(summon[Monoid[A]].unit)(combine)

So my question is: Does this even make sense in Scala and if so what do you think about changing the encoding to single parameter group ?

@odersky
Copy link
Contributor Author

odersky commented Mar 23, 2021

So my question is: Does this even make sense in Scala and if so what do you think about changing the encoding to single parameter group ?

That would be ambiguous. But you can write

(_ `combine` _)

if you want to be more symmetric.

@smarter smarter enabled auto-merge March 23, 2021 17:25
@smarter smarter merged commit f8bd01c into scala:master Mar 23, 2021
@smarter smarter deleted the fix-7613 branch March 23, 2021 18:17
odersky pushed a commit to dotty-staging/dotty that referenced this pull request Mar 24, 2021
Insert traits with implicit parameters as extra parents of classes
@Kordyjan Kordyjan modified the milestones: 3.0.0-RC2, 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.

Let traits with given clauses be implemented indirectly
4 participants