Skip to content
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

Syntax changes for new implicits #5825

Merged
merged 16 commits into from
Feb 4, 2019
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Jan 31, 2019

  • Use implied ... for instead of instance of
  • Use given instead of with
  • Reorganize docs from proposal to reference format

Direct link to docs, which together form a new part "Contextual Abstractions" in the reference.

  1. Implied Instances
  2. Inferable Parameters
  3. Context Bounds
  4. Extension Methods
  5. Implementing Typeclasses
  6. Typeclass Derivation
  7. Context Queries
  8. Implicit Conversions
  9. Inferable By-Name Parameters
  10. Relationship with Scala-2 Implicits

Note: I have tried in these docs to do without the term implicit entirely (OK, there's still implied). This was done in part as an experiment to see how far we can go. The other reason for doing it is that I have observed that we tend to use implicit quite indiscriminately and that the resulting terminology is not always precise and can be difficult to grasp for a newcomer. So I did this as an exercise in order to "wean myself off" the usage of the term. Once that's achieved we might decide that we want to bring back some usages of implicit, so this is not necessarily a permanent ban. Update: I went back to
"implicit conversion" - "inferable" felt too forced in that context.

Subsumes #5821. Follow-up to #5458.

@LPTK
Copy link
Contributor

LPTK commented Jan 31, 2019

How about deriving for parameters supposed to be automatically derived from their types?

def cell(str: String) deriving (r: Row) = ...

Then we can use the derive injunction to declare what should be derived:

  • for type class instances:
  derive ListOrd[A] for Ord[List[A]] deriving Ord[A] { ... }
  • and for explicitly-derived arguments:
  println(maximum(xs) derive descending) // force derivation into a specific direction
  println(maximum(xs) derive (descending derive IntOrd))

Expression maximum(xs) would have type derived Ord[T] => Option[T].

Finally, implicitly[T] could be written derive[T] (or derived[T] if the latter causes ambiguities):

val ord = derive[Ord[List[Int]]]

// or

val ord: Ord[List[Int]] = derive

The possible use of "deriving" was also mentioned by @drdozer in the original thread.

@odersky
Copy link
Contributor Author

odersky commented Jan 31, 2019

I believe derive clashes with typeclass derivation. derive already means we derive an implied instance
definition of a type, so to have it also mean derive a concrete value is confusing. Besides, I want to keep the scheme that parameter application and definition look exactly the same.

@odersky odersky force-pushed the change-implied branch 3 times, most recently from d0e4615 to b40b9d7 Compare January 31, 2019 15:02
@abgruszecki
Copy link
Contributor

abgruszecki commented Jan 31, 2019

if I could humbly propose rule as The Keyword?

rule Monoid[Int] { ... }
rule Trivial: Monoid[Unit] { ... }
rule OptionMonoid[A]: given Monoid[A] => Monoid[Option[A]] { ... }

It works quite well with the intution that we have "term inference" and we're defining rules for it. It's also, I think, easier to talk about "rules" than it is to talk about "implied instances". I'd say it's also easier to tell in all cases that this is a definition, as opposed to instance of X.

EDIT: Just to show this actually works quite well: a hypothetical error message when we have failed to infer a value could look as follows:

Failed to infer a value of type C. Following rules apply:
rule abc : given (A, B) => C
  (for A) rule fromZtoA: given Z => A
    (for Z) rule Z

But no value of type B could be inferred.

It's actually quite natural to talk about "rules" here. Also, previous propositions for import implicit and export implicit could now become import rule and export rule.

@drdozer
Copy link

drdozer commented Jan 31, 2019

My last contribution to the bike-shedding -- I think we're honing in on something that's a local minima though.

// declared with an in-place implimentation
derive OptionMonoid[A]: given Monoid[A] => Monoid[Option[A]] { ... }

// declared from a SAM
derive NegateOption[A]: given Negate[A] => Negate[Option[A]] = _.map(Negate.negate)

My reasoning is that derive at the beginning of a declaration can't be confused with derive at the end, but in both cases you are furnishing the compiler with instructions to make things for you - terms and implementations.

Being abile to use SAMs like this is a high priority for me.

Previously, `given ()`  was legal, but it serves no purpose and only complicates things.
Parser.syntaxError contains a tweak that underlines the whole span
of the current token, if it has a name. Tho make this work reliably
we need to reset the name to null when reading a new token, since not every
token sets a name.
It's `given A => B` instead of `A |=> B`.
# Conflicts:
#	tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TastyInterpreter.scala
#	tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TreeInterpreter.scala
Also: drop some doc pages that are no longer used.
Implied felt forced in this context
Token: INSTANCE -> IMPLIED
Flag: Contextual -> Given
@bmeesters
Copy link

Honest question, what is the benefit of using implied .. for and given instead of using instance .. of and with? Did anything else change w.r.t. the recently merged changes?

@odersky
Copy link
Contributor Author

odersky commented Feb 1, 2019

@bmeesters instance ... of had two strong counter arguments:

  • it is too generic, instance means generally any instance of a type, not the implied one.
  • it is too low level. Programmers associate instance ... of with {is,as}InstanceOf and get the
    wrong connotations.

given instead of with: Again, given is more specific than with, and furthermore it avoids
confusion with existing usages of with.

These are the only changes relative to #5458. The rest is a documentation reorg where everything that has to do with context abstractions is now combined in one chapter.

julienrf added a commit to julienrf/docs.scala-lang that referenced this pull request Feb 1, 2019
These links are likely to change again, but we probably have some
bikeshedding time before a consensus emerges from scala/scala3#5825
@buzden
Copy link
Contributor

buzden commented Feb 1, 2019

What I can't understand is: how (or whether) can I specify particular given parameters at the call-site in the case I want to specify only some of them. At least in some cases:

  • Multiple named in a single given list
   def f1[F[_], T](xs: F[T]) given (o: Ord[T], f: Functor[F]) = ???

   f1(whatever) given (o = IntOrd) // Can I pass the `given` parameter with a name?
  • Multiple unnamed in a single given list
   def f2[F[_], T](xs: F[T]) given (Ord[T], Functor[F]) = ???

   f2(whatever) given IntOrd // Can I pass only one?
  • Similarly typed, unnamed in different given lists
   def f3[F[_], G[_], T](xs: F[T], ys: G[T]) given (Ord[T], Functor[F]) given Functor[G] = ???

   f3 given GIsFunctor // How can I pass parameter to the second `given` list skipping the first?

@odersky
Copy link
Contributor Author

odersky commented Feb 2, 2019

What I can't understand is: how (or whether) can I specify particular given parameters at the call-site in the case I want to specify only some of them.

That's not in the scope of this PR, but it could be a good idea to add this.

@odersky odersky requested a review from biboudis February 2, 2019 13:40
@odersky
Copy link
Contributor Author

odersky commented Feb 2, 2019

@biboudis Can you give this a quick look? There's a lot of changes but it's all renamings or docs, so I think we should be able to merge this quickly.

@odersky odersky assigned biboudis and unassigned odersky Feb 2, 2019
@drdozer
Copy link

drdozer commented Feb 2, 2019

Is there a publicly visible build I can download with these changes in, or should I attempt to make one with git and sbt? I guess I'm asking if the checking process produces artifacts that we can use.


An implied alias instance defines an implied instance that is equal to some expression. E.g.,
```scala
implied ctx for ExecutionContext = currentThreadPool().context
Copy link
Contributor

Choose a reason for hiding this comment

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

I fail to see what is going on in this example. What is currentThreadPool()? At what scope it resides? I think a fuller example is required here.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's just an example I think, like implied ctx for ExecutionContext = ???.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess @soronpo meant that it would be useful to use a very commonly known pattern to make the intention of the example clearer.
People might be mislead by trying to understand what the example is actually trying to achieve...

something more common might be

implied ctx for ExecutionContext = myActorSystem.dispatcher

?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, but for me as a not frequenty Akka user currentThreadPool().context is certainly more intuitively understandable than myActorSystem.dispatcher

Copy link
Contributor

Choose a reason for hiding this comment

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

not if currentThreadPool doesn't exist in any known library...

but my example was just out-of-the-blue, something more common ćould be found

Copy link
Contributor

@biboudis biboudis left a comment

Choose a reason for hiding this comment

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

Looks very good

docs/docs/reference/contextual/instance-defs.md Outdated Show resolved Hide resolved
docs/docs/reference/contextual/instance-defs.md Outdated Show resolved Hide resolved
docs/docs/reference/contextual/instance-defs.md Outdated Show resolved Hide resolved
docs/docs/reference/contextual/inferable-params.md Outdated Show resolved Hide resolved
docs/docs/reference/contextual/query-types.md Outdated Show resolved Hide resolved
docs/docs/reference/contextual/query-types-spec.md Outdated Show resolved Hide resolved
@odersky odersky merged commit 3c50954 into scala:master Feb 4, 2019
@allanrenucci allanrenucci deleted the change-implied branch February 4, 2019 22:13
@Glavo
Copy link
Contributor

Glavo commented Feb 5, 2019

image

It seems that given is still shown as with in repl.

@allanrenucci
Copy link
Contributor

@Glavo Thanks for reporting. Can you please open an issue?

@biboudis biboudis added this to the 0.13 Tech Preview milestone Feb 6, 2019
@joshlemer
Copy link

Maybe someone could change the markdown links in the body of this PR (for posterity), they are all broken now.

@OlivierBlanvillain OlivierBlanvillain restored the change-implied branch February 6, 2019 15:45
@flomebul
Copy link
Contributor

Hello. In section "Extension Methods", subsection "Implied Instances for Extension Methods"
Is it "an for clause" instead of "an of clause" ?

@flomebul
Copy link
Contributor

Hello again. In section "Implicit Conversions", subsection "Examples", the type parameter "T" in se end of the second exemple ("def complete[T]") look like not used...

@OlivierBlanvillain
Copy link
Contributor

@flomebul Feel free to open a new PR to fix typos :)

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.