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

Rework reflect Constant API #10753

Merged

Conversation

nicolasstucki
Copy link
Contributor

Add types for specific constants as in the tasty format specification. This also aligns the API design with the rest of reflection by useing TypeTests (this inconsistency was noticed in #10738 (comment)).

- Constant.Int(x)
+ IntConstant(x)

- Constant.Long(x)
+ LongConstant(x)

...

Add types for specific constants as in the tasty format specification. This also aligns the API design with the rest of reflection by useing `TypeTest`s.

```diff
- Constant.Int(x)
+ IntConstant(x)

- Constant.Long(x)
+ LongConstant(x)

...
```
@nicolasstucki nicolasstucki added this to the 3.0.0-M3 milestone Dec 11, 2020
Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

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

It seems we have too many concepts here. Can we just keep one concept Constant as it's in the compiler?

class Constant(...) {
    def isByteRange: Boolean
    def isShortRange: Boolean
    def isCharRange: Boolean
    def isIntRange: Boolean    
    def isLongRange: Boolean
    def isFloatRange: Boolean
    def isNumeric: Boolean
    def isNonUnitAnyVal: Boolean
    def isAnyVal: Boolean

    def booleanValue: Boolean
    def byteValue: Byte
    def shortValue: Short
    def charValue: Char
    def intValue: Int
    def longValue: Long
    def floatValue: Float
    def doubleValue: Double
}

@nicolasstucki
Copy link
Contributor Author

That API does not allow you to know what the type of the constant is. It also does not provide concrete constructors.

@nicolasstucki
Copy link
Contributor Author

Those are all implementation details that are not really in TASTy

@nicolasstucki
Copy link
Contributor Author

This is the only part of the abstraction we can relly on being stable https://github.com/lampepfl/dotty/blob/master/tasty/src/dotty/tools/tasty/TastyFormat.scala#L134-L146

@nicolasstucki
Copy link
Contributor Author

It seems we have too many concepts here.

In this PR we do not increase the number of concepts, we just move them to follow the same API design as Trees and other abstraction.

@liufengyun
Copy link
Contributor

This is the only part of the abstraction we can relly on being stable https://github.com/lampepfl/dotty/blob/master/tasty/src/dotty/tools/tasty/TastyFormat.scala#L134-L146

It's indirectly decided by the language spec, which is more stable than TASTY.

Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

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

LGTM

I believe there is room to have simpler and cleaner APIs without introducing so many concepts. But as the usability aspect is subjective, and the constant APIs are not commonly used in meta-programming, thus I think the changes are fine.

@nicolasstucki nicolasstucki merged commit 4d0a7d8 into scala:master Dec 11, 2020
@nicolasstucki nicolasstucki deleted the rework-reflect-constant-API branch December 11, 2020 14:07
@deusaquilus
Copy link
Contributor

deusaquilus commented Dec 15, 2020

I think this is a Much uglier API then before. Compare this:

      term match
        case Literal(StringConstant(v: String)) => Some(v)
        case Literal(IntConstant(v: Int)) => Some(v)
        case Literal(LongConstant(v: Long)) => Some(v)
        case Literal(BooleanConstant(v: Boolean)) => Some(v)
        case Literal(FloatConstant(v: Float)) => Some(v)
        case Literal(DoubleConstant(v: Double)) => Some(v)
        case Literal(ByteConstant(v: Byte)) => Some(v)
        case _ => None

To this:

      term match
        case Literal(Constant.String(v: String)) => Some(v)
        case Literal(Constant.Int(v: Int)) => Some(v)
        case Literal(Constant.Long(v: Long)) => Some(v)
        case Literal(Constant.Boolean(v: Boolean)) => Some(v)
        case Literal(Constant.Float(v: Float)) => Some(v)
        case Literal(Constant.Double(v: Double)) => Some(v)
        case Literal(Constant.Byte(v: Byte)) => Some(v)
        case _ => None

This StringConstant, IntConstant, etc... reminds me of Java's Hadoop's IntWritable, LongWritable, DoubleWritable. That was a nasty way of doing things I was hoping I would not need to work with again.

Can we at least have Constant.String, Constant.Int etc... available as an unapply?

@nicolasstucki
Copy link
Contributor Author

Actually you just need

 term match
        case Literal(StringConstant(v)) => Some(v)
        case Literal(IntConstant(v)) => Some(v)
        case Literal(LongConstant(v)) => Some(v)
        case Literal(BooleanConstant(v)) => Some(v)
        case Literal(FloatConstant(v)) => Some(v)
        case Literal(DoubleConstant(v)) => Some(v)
        case Literal(ByteConstant(v)) => Some(v)
        case _ => None

@deusaquilus
Copy link
Contributor

That makes sense. Thanks!
I still like the one with dots more 😊

@nicolasstucki
Copy link
Contributor Author

I also liked it but it made more sense to change it for the sake of consistency with the rest of the API. This will help with doc navigation which is already non-trivial.

@deusaquilus
Copy link
Contributor

Could I somehow wire this up myself? I recall in Scala 2 trying to do implicit class FooExt(fooObject: Foo.type) { ... } would crash the compiler. Is it possible to add extensions methods to an object with Scala 3?

@Kordyjan Kordyjan modified the milestones: 3.0.0-M3, 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.

4 participants