Skip to content

Change syntax of given whitebox macros #8619

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

Closed
odersky opened this issue Mar 26, 2020 · 17 comments
Closed

Change syntax of given whitebox macros #8619

odersky opened this issue Mar 26, 2020 · 17 comments

Comments

@odersky
Copy link
Contributor

odersky commented Mar 26, 2020

Status quo

inline def whiteBox1 <: T = ...
inline given whiteBox2 as _ <: T = ...

Critique

  • Syntax is not consistent
  • You could argue that the first syntax is too quiet and also misleading since at first glance whiteBox1 is in the position where you would expect to see a type.
  • _ <: T is technically wrong (or, rather, old style) since it suggests a lambda. We are after an existential instead.

Proposal

Write ? <: T (analogous to a wildcard type argument) to express both forms of whitebox macros. I.e.

inline def whiteBox1: ? <: T = ...
inline given whiteBox2 as ? <: T = ...

Opinions?

@smarter
Copy link
Member

smarter commented Mar 26, 2020

? <: T makes me think I can put something other than ? on the left which is not the case. If we need to change the syntax I would rather use an extra keyword to denote whiteboxity (I think whitebox is fine since it's well-established Scala jargon).

@odersky
Copy link
Contributor Author

odersky commented Mar 26, 2020

Or transparent?

@abgruszecki
Copy link
Contributor

I actually like the ? <: T syntax - it expresses the "unknown subtype of T" concept well.

Reg. trying to replace ? with another type - to me doing that would result in something that reads like nonsense, so I'm not sure if very many people will try to do that. Consider:

inline def foo : ? <: String === "define an inline foo that returns some subtype of String"
inline def foo : "a" <: String == "define an inline foo that returns "a", which is a subtype of String"

@smarter
Copy link
Member

smarter commented Mar 26, 2020

The problem is that:

inline def foo : ? <: String

is very different semantically from:

inline def foo : List[? <: String]

The latter is not whitebox at all, even though it uses a very similar syntax.

@abgruszecki
Copy link
Contributor

Hm, you may be right and it may be too cute. How would the keyword syntax look? Like this?

inline whitebox def foo : String =

@smarter
Copy link
Member

smarter commented Mar 26, 2020

whitebox inline def I'd say, whitebox is a modifier of inline.

@abgruszecki
Copy link
Contributor

The part that I am slightly miffed about is that we would lose the "this is not an actual type annotation" suggestion that the current syntax foo <: String expresses. Might not be a big loss, all things considered.

@odersky
Copy link
Contributor Author

odersky commented Mar 26, 2020

I'd go for transparent inline. whitebox is too much expert speak. Also, it works better in conjunction with blackbox but we do not have that one as a modifier.

@therealcisse
Copy link
Contributor

How about ?

inline def whiteBox1 : ?String
inline given whiteBox2 as ?T = ...

This was propose and rejected for nullable types.

@nicolasstucki
Copy link
Contributor

Finally, I have always thought that this feature deserved a flag. We currently have no way to know if an inline method is whitebox or not after it is typed.

@milessabin
Copy link
Contributor

Scala 2 accidentally treats an empty refinement as "do not widen" indicator. Could we make that official and use it here,

inline def foo : String {} ...

@nicolasstucki
Copy link
Contributor

We should have a syntax where not widening would not happen by mistake.

@odersky
Copy link
Contributor Author

odersky commented Mar 30, 2020

I am not sure about the flag. We are currently trying hard to reduce the number of flags that we pickle. Even without a flag., there could be a robust predicate on symbols indicating whether an inline function is blackbox or whitebox Namely, an inline function f such as

inline def f(): T = rhs

is blackbox if rhs is of the form E: T1 where T =:= T1 (we only need to test T <:< T1, the other direction holds anyway). If that's the case, the expansion of f cannot change the type, which is what
characterizes a blackbox macro. Now it's true that if someone writes

transparent inline def f(): T = E: T

that also gives a blackbox macro according to our definition, despite the transparent. But I'd argue that's OK, and even desirable: we capture that way the semantics of a blackbox macro, not the syntactic representation.

@sjrd
Copy link
Member

sjrd commented Mar 30, 2020

We are currently trying hard to reduce the number of flags that we pickle.

Why though? That sounds like a useless target metric. What's important is to pickle the semantics of the language, and not a particular encoding of the language. It should add simple as possible, sure, but not simpler.

You can argue that the semantics of blackbox macros is a whitebox macro with an ascription. But then that's also how you have to specify the language. And that means that you cannot explain blackbox macros without explaining whitebox macros. That doesn't seem like a good deal to me.

@nicolasstucki
Copy link
Contributor

Note that we will need as a flag (or at least in the TASTy file) for #7825.

odersky added a commit that referenced this issue Mar 31, 2020
Fix #8619: Demand `transparent` for whitebox inlines
@odersky
Copy link
Contributor Author

odersky commented Mar 31, 2020

Note that we will need as a flag (or at least in the TASTy file) for #7825.

What I had in mind was a method isBlackboxInline on symbols that implements the logic I outlined before. That method should give valid results for methods coming from Tasty as well. So we would not need a flag.

@odersky
Copy link
Contributor Author

odersky commented Mar 31, 2020

Here's the ruleset:

  • A blackbox macro is a macro that on inline expansion keeps its type
  • A normal inline method always keeps its type since its inline expansion is ascripted with its result type. That's a desugaring step, not relevant for Tasty.
  • A transparent inline does not get ascripted, so it might be a whitebox macro (and probably will be, in most cases).

That means we can treat whitebox/blackboxity without having to change the Tasty format. The Tasty format remains smaller, which is a win in my book.

It also removes some magic from the inlining. Otherwise we'd have to specify differences of inline expansion for blackbox and for whitebox macros. One gets its type widened on expansion, the other does not. By pushing it all into desugaring (ascribe or not) we avoid this added complexity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants