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

Can ToString[.] type be made applicable to arbitrary type by converting its symbol name as singleton? #182

Open
tribbloid opened this issue Mar 28, 2021 · 10 comments

Comments

@tribbloid
Copy link

I have posted a stackoverflow question on this:

https://stackoverflow.com/questions/66837880/how-to-get-the-name-of-a-class-as-a-string-literal-at-compile-time-using-shapele

According to Prof. @DmytroMitin, it appears that a whitebox macro is the only option, fortunately it is not too complex, in dotty it may be introduced as a compiletime ops later

This feature, combining with RequireMsg[.] type, can be used to throw a customised ops error at compile-time, using a string interpolated with custom user type (https://twitter.com/soronpo/status/1275014596034809856). Similar to how @implicitNotFound error message is interpolated in native scala:

@implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.")
sealed abstract class =:=[From, To] extends (From <:< To) with Serializable {
...
}

Do you think this will be useful? I can submit a PR shortly but I may need some guidance to circumvent the NonLiteral constraint

@soronpo
Copy link
Collaborator

soronpo commented Mar 29, 2021

It shouldn't be ToString, but GetNameOfSym. I think it's ok to add. But maybe another way is better- the way string interpolation is currently done inside the implicitNotFound message. We just add this ability directly to the RequireMsg functionality.

@tribbloid
Copy link
Author

Thanks a lot, I didn't find any test case for RequireMsg with such feature, is there a class name I should focus on?

@tribbloid
Copy link
Author

Oh sorry I misunderstood it, I thought it is already being done. We still need to write it.

So you prefers to allow RequireMsg to take more type arguments and expand each ${} in the second arg (Msg) with symbol name of 3+ args? How many args can you support at maximum (without using annotation like @ImplicitNotFound)?

The GetNameOfSym seems to be a bit easier to me.

@soronpo
Copy link
Collaborator

soronpo commented Mar 30, 2021

No. What I mean is that message string inside it will support "${sym}"

@tribbloid
Copy link
Author

I see, but how does RequireMsg know what "${From}" or "${To}" refers to? They are just type arguments that are not in the scope

@soronpo
Copy link
Collaborator

soronpo commented Mar 30, 2021

The same way RequireMsg is determines what symbol to apply the implicitNotFound annotation on.
Actually, I haven't tried it, but I wouldn't be surprised if it works as-is.

@soronpo
Copy link
Collaborator

soronpo commented Mar 30, 2021

Yes, apparently it works:

trait Foo[T]
object Foo {
  implicit def ev[T](implicit r : RequireMsg[false, "Bad Type: ${T}"]) : Foo[T] = ???
}
implicitly[Foo[Int]] //error: Bad Type: Int

@tribbloid
Copy link
Author

Nice! So it addressed the most simple case.

For more complex case it we may still need the GetNameOfSym. Invoking type members by A#B doesn't work though:

  trait HasM {

    type M = Int
  }

  trait Foo[T]

  object Foo {

    implicit def ev[T <: HasM](
        implicit
        r: RequireMsg[false, "Bad Type: ${T#M}"]
    ): Foo[T] = ???
  }
  implicitly[Foo[HasM]] //error: Bad Type:

It can get even more hairy if ${T} is replaced with all kinds of dependent types. So it make sense to be more specific about the exact operation to string

@soronpo
Copy link
Collaborator

soronpo commented Mar 31, 2021

I think it's maybe better to add the dependent type interpolation support in the compiler itself.
I propose opening a thread on contributors.scala-lang.org to discuss this further.

@tribbloid
Copy link
Author

@soronpo I'm not a compiler's guy. But to me it appears to be never documented as a scala 2 feature or language specification. Even the original @ImplicitNotFound argument doesn't list it as a feature, I could only speculate that from the example in =:=. You may have a better chance to convince dotty team to support it.

NameOfSym or NameOfClass on the other hand can be used to ensure that a type must be from a certain package or so. Maybe worths a try.

Also it could serve as the default ToString[.] impl for custom operands defined by OpIntercept (https://twitter.com/soronpo/status/1275014596034809856/photo/2)

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

No branches or pull requests

2 participants