-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Change to given/using syntax #8162
Conversation
This looks great to me, the only wrinkle is that 2.13 also has something called Using, which will make googling a bit harder: https://www.scala-lang.org/api/current/scala/util/Using$.html, I don't think that's a showstopper though. |
maximum(xs).with(descending.with(listOrd.with(intOrd))) | ||
maximum(xs)(using descending) | ||
maximum(xs)(using descending(using listOrd)) | ||
maximum(xs)(using descending(using listOrd(using intOrd))) | ||
``` | ||
|
||
## Multiple With Clauses |
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.
## Multiple With Clauses | |
## Multiple Using Clauses |
@@ -143,7 +143,7 @@ extension listOps on [T](xs: List[T]) { | |||
def third: T = xs.tail.tail.head | |||
} | |||
|
|||
extension on [T](xs: List[T]) with Ordering[T] { | |||
extension on [T](xs: List[T])(using Ordering[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.
Are these changes indented in the not new section ?
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 they are not. Thank for pointing it out!
Big thumbs up for having context parameters in parentheses. This solves a lot of problems. Btw the docs link isn't working. |
I find using |
ditching infix 👍 using two different words in the two positions 👍 but (I'm well aware this is circling back to something previously suggested, but it wouldn't be the first such circling-back:) what about |
I've always liked |
That's a nice improvement! This is the first time it's felt mostly acceptable to me, which given how critical I am, is some sort of non-negligible praise. My remaining serious concern is that I don't think the Is it a noun? Well,
Okay, that works, except it's just a subject (or object) of a sentence; it's just a sentence fragment. You'd expect something like
Then we're all good: the sentence is over, we can understand it, breathe a sigh of relief, and move on. Otherwise it leaves you hanging. Or is it an adjective, like
Still leaves you hanging, and the adjective as type form is bizarre. Or is it a preposition, like
Prepositions link parts of sentences, so these forms--especially the
Note here that So the only interpretation that's marginally comfortable is the noun form, and even that doesn't work well as it's a sentence fragment. So what's the problem? If it's the noun form we're using, we have no verb. If it's some other form we're using, it's creating a very awkward construct at least in English, where the block structure doesn't match what the grammar suggests. Note that in mathematics, the main usage of Now, the imperative verb form,
And note that the prepositional form is great where we have
So I think although we can get used to the current form, it's still not very natural. It's more of a struggle to understand because of how the usage clashes with standard grammar and/or standard usage in English. So my least disruptive suggestion is to switch to verb form Overall I think it is very important not to make the main code feel weird in order to have less weird-feeling import statements. import com.org.edu.orderings.{ _, using _ }
give listOrd[T] as List[Ord[T]] {
def compare(ls: List[T], rs: List[T]) = ...
}
def second[T](xs: List[T])(using ord: List[Ord[T]]) = ...
second(foo)(using myCustomListOrd) Is it a huge deal? No. But I think it will feel considerably more natural. For a slightly larger change with more bikeshedding, import com.org.edu.orderings.{ _, provide _ }
provide listOrd[T] as List[Ord[T]] { ... }
def second[T](xs: List[T])(given ord: List[Ord[T]])
second(foo)(provide myCustomListOrd) tl;dr I think |
The problem with verbs such as You can't do that with Of course, a noun would be the ideal, but that has been elusive. It's easy to find nouns that work for typeclasses, but not for context passing, and certainly not for both. |
Amen! The other alternative which hasn't received due consideration is to use Chinese characters. They are shorter than verbose English words and generally circumvent the grammatical conundrums that have plagued these discussions. Also, why shouldn't Scala be the language that introduces Chinese characters to coders world-wide? My spouse is Chinese, and when she's yelling at the daughter, I don't always understand what is at issue, but generally I am comfortable now with the writing system. 礼 is the simplified 禮 so probably for coding I would go with simplified. I don't know what choices actual coders make. We have a team in Shanghai, but I don't have a chance to work with them. Apparently Shanghai is expensive with respect to Bangalore? So probably there are other linguistic opportunities that are available. The nice thing about the Chinese character is that it implies a ritual offering -- I was trying to remember that word, "offering", Bach's musikalisches Opfer is like Abraham and Isaac, a sacrifice. A "given" is not merely a logical assumption, but a solemn commitment that may determine the course of an entire project. I suppose one could also propose "offering", in that vein. |
This reverts commit 04095bc. # Conflicts: # compiler/src/dotty/tools/dotc/parsing/Parsers.scala # compiler/src/dotty/tools/dotc/parsing/Tokens.scala # docs/docs/internals/syntax.md # tests/neg-macros/delegate-match-1/Macro_1.scala # tests/neg-macros/delegate-match-2/Macro_1.scala # tests/neg-macros/delegate-match-3/Macro_1.scala # tests/neg-macros/i6432/Macro_1.scala # tests/neg-macros/i6432b/Macro_1.scala # tests/neg-macros/i6976/Macro_1.scala # tests/neg-macros/inline-case-objects/Macro_1.scala # tests/neg-macros/inline-macro-staged-interpreter/Macro_1.scala # tests/neg-macros/inline-option/Macro_1.scala # tests/neg-macros/inline-tuples-1/Macro_1.scala # tests/neg-macros/macros-in-same-project-6/Foo.scala # tests/neg-macros/quote-error-2/Macro_1.scala # tests/neg-macros/quote-error/Macro_1.scala # tests/neg-macros/quote-exception/Macro_1.scala # tests/neg-macros/quote-whitebox/Macro_1.scala # tests/neg-macros/reflect-inline/assert_1.scala # tests/neg-macros/tasty-macro-assert-1/quoted_1.scala # tests/neg-macros/tasty-macro-assert-2/quoted_1.scala # tests/neg-macros/tasty-macro-error/quoted_1.scala # tests/neg-macros/tasty-macro-positions/quoted_1.scala # tests/neg-macros/tasty-string-interpolator-position-a/Macro_1.scala # tests/neg-macros/tasty-string-interpolator-position-b/Macro_1.scala # tests/neg/given-eta.scala # tests/neg/i7919.scala # tests/neg/implicit-params.scala # tests/pending/run/tasty-comments/quoted_1.scala # tests/pos-custom-args/erased/i7868.scala # tests/pos-macros/i6171/Macro_1.scala # tests/pos-macros/i6535/Macro_1.scala # tests/pos-macros/i6803b/Macro_1.scala # tests/pos-macros/i7011/Macros_1.scala # tests/pos-macros/quote-nested-object/Macro_1.scala # tests/pos-macros/quote-whitebox-2/Macro_1.scala # tests/pos-macros/tasty-constant-type/Macro_1.scala # tests/pos-macros/treemap-unapply/Macro.scala # tests/pos/i7204.scala # tests/pos/i7532.scala # tests/run-custom-args/Yretain-trees/tasty-definitions-2/Macro_1.scala # tests/run-custom-args/Yretain-trees/tasty-definitions-3/Macro_1.scala # tests/run-custom-args/Yretain-trees/tasty-extractors-owners/quoted_1.scala # tests/run-custom-args/Yretain-trees/tasty-load-tree-1/quoted_1.scala # tests/run-custom-args/Yretain-trees/tasty-load-tree-2/quoted_1.scala # tests/run-custom-args/run-macros-erased/reflect-isFunctionType/macro_1.scala # tests/run-macros/f-interpolation-1/FQuote_1.scala # tests/run-macros/gestalt-type-toolbox-reflect/Macro_1.scala # tests/run-macros/i4735/Macro_1.scala # tests/run-macros/i4803/Macro_1.scala # tests/run-macros/i4803b/Macro_1.scala # tests/run-macros/i4803c/Macro_1.scala # tests/run-macros/i5119/Macro_1.scala # tests/run-macros/i5119b/Macro_1.scala # tests/run-macros/i5188a/Macro_1.scala # tests/run-macros/i5533/Macro_1.scala # tests/run-macros/i5533b/Macro_1.scala # tests/run-macros/i5536/Macro_1.scala # tests/run-macros/i5629/Macro_1.scala # tests/run-macros/i5715/Macro_1.scala # tests/run-macros/i5941/macro_1.scala # tests/run-macros/i6171/Macro_1.scala # tests/run-macros/i6270/Macro_1.scala # tests/run-macros/i6518/Macro_1.scala # tests/run-macros/i6679/Macro_1.scala # tests/run-macros/i6765-c/Macro_1.scala # tests/run-macros/i6765/Macro_1.scala # tests/run-macros/i6988/FirstArg_1.scala # tests/run-macros/i7898/Macro_1.scala # tests/run-macros/i7964/Macro_1.scala # tests/run-macros/inferred-repeated-result/test_1.scala # tests/run-macros/inline-case-objects/Macro_1.scala # tests/run-macros/inline-macro-staged-interpreter/Macro_1.scala # tests/run-macros/inline-option/Macro_1.scala # tests/run-macros/inline-tuples-1/Macro_1.scala # tests/run-macros/inline-tuples-2/Macro_1.scala # tests/run-macros/inline-varargs-1/Macro_1.scala # tests/run-macros/quote-and-splice/Macros_1.scala # tests/run-macros/quote-inline-function/quoted_1.scala # tests/run-macros/quote-matcher-power/Macro_1.scala # tests/run-macros/quote-matcher-runtime/quoted_1.scala # tests/run-macros/quote-simple-macro/quoted_1.scala # tests/run-macros/quote-toExprOfTuple/Macro_1.scala # tests/run-macros/quote-type-matcher/quoted_1.scala # tests/run-macros/quote-whitebox/Macro_1.scala # tests/run-macros/quoted-expr-block/quoted_1.scala # tests/run-macros/quoted-matching-docs/Macro_1.scala # tests/run-macros/refined-selectable-macro/Macro_1.scala # tests/run-macros/reflect-dsl/assert_1.scala # tests/run-macros/reflect-inline/assert_1.scala # tests/run-macros/reflect-lambda/assert_1.scala # tests/run-macros/reflect-pos-fun/assert_1.scala # tests/run-macros/reflect-select-constructor/assert_1.scala # tests/run-macros/reflect-select-copy-2/assert_1.scala # tests/run-macros/reflect-select-copy/assert_1.scala # tests/run-macros/reflect-select-symbol-constructor/assert_1.scala # tests/run-macros/reflect-select-value-class/assert_1.scala # tests/run-macros/reflect-typeChecks/assert_1.scala # tests/run-macros/requiredSymbols/Macro_1.scala # tests/run-macros/tasty-argument-tree-1/quoted_1.scala # tests/run-macros/tasty-custom-show/quoted_1.scala # tests/run-macros/tasty-dealias/quoted_1.scala # tests/run-macros/tasty-definitions-1/quoted_1.scala # tests/run-macros/tasty-eval/quoted_1.scala # tests/run-macros/tasty-extractors-1/quoted_1.scala # tests/run-macros/tasty-extractors-2/quoted_1.scala # tests/run-macros/tasty-extractors-3/quoted_1.scala # tests/run-macros/tasty-extractors-types/quoted_1.scala # tests/run-macros/tasty-getfile/Macro_1.scala # tests/run-macros/tasty-interpolation-1/Macro.scala # tests/run-macros/tasty-linenumber-2/quoted_1.scala # tests/run-macros/tasty-linenumber/quoted_1.scala # tests/run-macros/tasty-location/quoted_1.scala # tests/run-macros/tasty-macro-assert/quoted_1.scala # tests/run-macros/tasty-macro-const/quoted_1.scala # tests/run-macros/tasty-macro-positions/quoted_1.scala # tests/run-macros/tasty-original-source/Macros_1.scala # tests/run-macros/tasty-seal-method/quoted_1.scala # tests/run-macros/tasty-simplified/quoted_1.scala # tests/run-macros/tasty-subtyping/quoted_1.scala # tests/run-macros/tasty-tree-map/quoted_1.scala # tests/run-macros/tasty-typeof/Macro_1.scala # tests/run-macros/tasty-unsafe-let/quoted_1.scala # tests/run-macros/type-show/Macro_1.scala # tests/run-macros/xml-interpolation-1/XmlQuote_1.scala # tests/run-macros/xml-interpolation-2/XmlQuote_1.scala # tests/run-macros/xml-interpolation-3/XmlQuote_1.scala # tests/run-with-compiler/i6201/macro_1.scala # tests/run/given-eta.scala
While that would expand considerably the space of potential options, it might cause trouble with editors (or at least that's the justification given for avoiding non-ascii characters given by scalastyle) |
@kavedaa - You've just used a verb there, Also, Nouns don't work with |
You're nitpicking. :) It's hard form complete sentences without verbs. However, if we say "let there be defined a
Or "a method definition".
Or "an import". Although, yes, I would read it as "do import".
"Let there be defined, for any type T ... a given instance for Ord of List of T with the following implementation." In other words, one instance for every, or any, type T. (It's not quite precise, "generator of given instances" might be closer.)
I agree about |
@kavedaa - Grammar is all about nits! Good point about Er, wait, never mind. I don't think it's really any better at avoiding the hanging-awaiting-the-rest-of-the-sentence feeling. It's just better because it denotes filling a role rather than being something which it isn't. (And Rust uses it: |
In If we colloquially shorten "given instance" to "given", it would be "a given, named intOrd, for Ord of Int". |
Now that Scala takes trailing commas, it should leverage more commas everywhere. Comma could be the new semi-colon. |
8e02da9
to
9e86124
Compare
Convert all files that had a conflict in the last commit, which reverted `with` clauses to `given` parameters.
9e86124
to
a18bc9e
Compare
@kavedaa - Okay, there exists a grammatically correct way to use My entire comment surrounds making the linguistic interpretation as simple as possible, so that the most natural reading suggests the right things. |
@@ -3,7 +3,7 @@ import scala.quoted.matching._ | |||
|
|||
inline def f: Any = ${ fImpl } | |||
|
|||
private def fImpl with (qctx: QuoteContext) : Expr[Unit] = { | |||
private def fImpl (using qctx: QuoteContext) : Expr[Unit] = { |
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.
We should revert back to the version without extra spaces
private def fImpl(using qctx: QuoteContext): Expr[Unit] = {
@@ -7,6 +7,6 @@ object Bar { | |||
|
|||
inline def myMacro(): Unit = ${ aMacroImplementation } | |||
|
|||
def aMacroImplementation with QuoteContext : Expr[Unit] = '{} | |||
def aMacroImplementation(given QuoteContext): Expr[Unit] = '{} |
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.
Should be
def aMacroImplementation(using QuoteContext): Expr[Unit] = '{}
same for other (given QuoteContext):
is the tests.
tests/neg/i7425.scala
Outdated
@@ -2,7 +2,7 @@ class C { def f: Int = 0 } | |||
|
|||
trait D { def f(): Int = 0 } | |||
|
|||
def foo1(x: C & D) = x.f // error: method f must be called with argument | |||
def foo1(x: C & D) = x.f // error: method f must be called(using ) argument |
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.
def foo1(x: C & D) = x.f // error: method f must be called(using ) argument | |
def foo1(x: C & D) = x.f // error: method f must be called with argument |
@@ -12,7 +12,7 @@ object XmlQuote { | |||
${XmlQuote.impl('ctx, 'args)} | |||
} | |||
|
|||
def impl(receiver: Expr[StringContext], args: Expr[Seq[Any]]) with QuoteContext : Expr[Xml] = { | |||
def impl(receiver: Expr[StringContext], args: Expr[Seq[Any]]) (using QuoteContext): Expr[Xml] = { |
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.
def impl(receiver: Expr[StringContext], args: Expr[Seq[Any]]) (using QuoteContext): Expr[Xml] = { | |
def impl(receiver: Expr[StringContext], args: Expr[Seq[Any]])(using QuoteContext): Expr[Xml] = { |
And other similar cases
@SethTisue @Ichoran It's true that a verb form can work better in some situations (even though given Position = tree.pos That reads OK: "the given position is tree.pos". But with a verb it would be give Position = tree.pos That does not work as well. It's pidgin english, and mixes terms and types in nonsensical ways. After extensive experience, I have come to really like In short I have become quite comfortable with |
👍 for splitting into 2 keywords, 1 for introduction, 1 for condition But giving listOrd[T](given Ord[T]) as Ord[List[T]] { ... } gift listOrd[T](given Ord[T]) as Ord[List[T]] { ... } providing listOrd[T](given Ord[T]) as Ord[List[T]] { ... } provider listOrd[T](given Ord[T]) as Ord[List[T]] { ... } provision listOrd[T](given Ord[T]) as Ord[List[T]] { ... } offer listOrd[T](given Ord[T]) as Ord[List[T]] { ... } offering listOrd[T](given Ord[T]) as Ord[List[T]] { ... } |
Context has been used to describe implicits before so why not context listOrd[T](given Ord[T]) as Ord[List[T]] { ... }
def max[T](x: T, y: T)(given Ord[T]): T = ...
max(xs, ys)(given listOrd)
context as ExecutionContext = ExecutionContext.global context as Monad[Option] { ... } and |
I plan on merging this tomorrow to make it into the release. |
@odersky - I'm not arguing that one can't get used to it. I expect one can, especially the given/using form. I'm arguing that it given looks weird on first glance. What doesn't work so well is when you're using something that needs to be used as a noun, but it isn't obviously a noun when you encounter it the first time. That's where the other uses favor verbs, or favor not using "Elephant Bruce as Mayor." This isn't really a sentence, is it? Even if you might find it on election materials. "given bruce as Mayor { def laws = None }" You have to stick in a bunch of extra words to rescue the grammar. "let the given be bruce, which is defined as Mayor { def laws = None }" If you use a verb, it works just fine, because it's just like "give chocolate as a present". And if you use a word that has multiple grammatical uses and the initial parsing suggests the wrong form, you get exactly the same phenomenon in the trick phrase, "Fruit flies like a banana". It's hard to parse. (Indeed, in this case, there are two perfectly valid meanings depending on whether "flies" is a verb or a (pluralized) noun, though one of the two meanings is kind of weird.) Especially with Anyway, I'm sure most everyone can eventually get used to it. I'm not sure if it might put off a substantial number of people without them realizing why, just having a feeling that it's "wrong". Again, I think it's okay the way it is. As I said, the given/using pair is the first one that actually feels sufficiently comfortable to me. Once I'm used to it, it will be fine. But I think, inasmuch as natural language grammar is objective, that @amsayk - No thank you; that's a very weird form grammatically. |
I suspect I'm going to lose this argument, but I have to protest again that you're overstating your claims of what does and does not work as English:
No, sorry -- that reads as "give the Position as tree.pos", which is decent, just different. Both versions require silently introducing additional parts of speech to read as English; both read adequately, if imperfectly. And "as" is a reasonable reading of Really, I think that what you are arguing for here as "English" is essentially a very specific dialect. I strongly suspect that your preference for the first form is because it is pronounced like a traditional mathematical lemma -- which it totally is, but I doubt that one programmer in a hundred actually finds that an intuitive way of thinking about their programs. I'll say again (as a native speaker of English and amateur linguist for 30+ years) that the verbal variant communicates its meaning and intent more clearly to me, and your claims that one reads correctly as English and the other doesn't just aren't true. You're rationalizing a preference here, not arguing from linguistic truth, and I wish you'd stop claiming a linguistic high ground that you don't have here... |
@jducoeur - I think you're correct but you could be more polite about it :) When you get used to a particular parsing of something, it's easy to argue from assuming that parse, not noticing that when you change forms an alternate parse is completely natural. (We generally design computer languages to not have this property, as it admits too much ambiguity, but in natural language it comes up all the time.) So I think it's a very understandable mistake. But I agree it's a mistake. Both forms parse fine, just into different trees. |
Sorry -- currently sick and about to leave for a funeral. Apologies if that came off as too sharp. |
The curse and blessing of
So which form is it that is used in Consider this example: "I will give him $10000 as compensation for his damages." Or more general: "To give something as compensation." So as far as I can see, both (I'm not arguing for either form here, just trying to investigate. I think much of the discussion around |
@kavedaa - That's a good point. Note, however, that the |
|
I don't think the objection to the noun form of But we can't debate this forever, so moving forward while allowing for an alternate consensus sounds reasonable to me. |
I'm really happy about the decision to use two separate keywords here, but I have a little suggestion: how about |
I have a different issue with this syntax. When I see given listOrd[T](using ord: Ord[T]) as Ord[List[T]] I read it as "given (a) listOrd (using ord as Ord[List[T]". It isn't really natural for me to associate the "as Ord[List[T]]" with the listOrd rather than the ord, even with parentheses. If I'm being honest, I think |
Some viewpoints of course will fall squarely within the alternate consensus. The difference between Scala and the Iowa caucus is that here the community has only a benevolent dictator to contend with. |
This is a (hopefully final) tweak to the syntax of givens.
Thesis: The Status Quo:
The current (Dotty 0.21) implementation uses
given
in three rolesIt was felt that this was too much. It's makes programs less readable since it is hard to see at a glance in what role a
given
is used. People voiced the concern whether we would not simply repeating the problems with overusedimplicit
s, just replacingimplicit
withgiven
.Antithesis: The Alternative
The alternative implemented in current master is to use
given
for instanceswith
for context parameters.with(...)
for context arguments?=>
for context functionsThat nicely distinguishes different kinds of uses. But people felt that infix
with
had problems. Some usages read really nice with it but for others we run into problems of layout and possibly false ways to read it. One problem that was not voiced yet is this:In colloquial usage
A with B as C
readsA with (B as C)
but the definition above should be read as(A with B) as C
instead.Synthesis
We still want to distinguish uses of givens but want to avoid infix syntax for context parameters. So let's keep givens and context functions as in the alternative proposal but express context parameters and arguments with
using
(inside parens) instead. E.g.This PR changes the docs according to the new syntax. To get started:
https://github.com/dotty-staging/dotty/blob/change-given-using/docs/docs/reference/contextual/motivation-new.md