Is it possible to implement trait as Proxy in scala3 by using macro?
For example, if I have a trait
trait PrintService:
def printString(str: String): Unit
I would like to implement some kind of HTTP proxy by scala3 macro that would call a remote service.
I've tried with
val repr = TypeRepr.of[T].typeSymbol.declarations
but it returns only
List(method equals, method getClass, method $isInstanceOf$, method asInstanceOf, method $asInstanceOf$, method ##, method ==, method !=, method hashCode, method isInstanceOf, method toString)
Related
Just looking at Scala Akka and wondering what is the difference between the following object initialisation methods.
system.actorOf(Props[HelloActor], name = "helloactor")
and
system.actorOf(Props(new HelloActor("Fred")), name = "helloactor")
I can understand the second one, Props(new HelloActor()), but what is the first one, Props[HelloActor]? I don't know its name so can't google for it.
Props is a case class with a companion object. In Scala code you will see two major ways people will construct objects. One is with a constructor on a class. Another major way is by calling an apply() method on a companion object.
If you look at the source code of akka.actor.Props you will notice that the companion object has four apply() methods, two of which you are referencing in your code above. At time of writing their signatures are:
def apply[T <: Actor: ClassTag](): Props
def apply[T <: Actor: ClassTag](creator: ⇒ T): Props
As helpful sugar Scala allows you to call an apply method without stating the apply method so in your first example you can rewrite that as Props[HelloActor]() and the compiler inserts the apply() method for you. Next, if a method has no arguments you may omit the parenthesis. So the call becomes Props[HelloActor] as you have pointed out above.
Your second example calls the second apply() method.
As to your question about how does the real HelloActor class get instantiated that is a little more complicated. All of the explicitly defined apply() methods eventually call a special apply() method that is generated by the nature of Props being a case class. This apply calls the constructor on Props which creates an akka.actor.IndirectActorProducer. This class holds many strategies that can be used to instantiate the actor. In your simple case it eventually uses reflection to construct your actor.
Square brackets [] in Scala denote the use of a generic class. Generic classes are classes which take a type as a parameter. The class name between the brackets in the instantiation of a generic class is the argument for that type parameter.
So in your case, the Props class has 1 generic parameter, and the line Props[HelloActor] is providing the type HelloActor as the argument for that generic parameter.
Part I
Suppose I have a type class trait Show[T] { def print(t: T): String } with instances for String and Int. Suppose I have a value whose specific type is known only at runtime:
val x: Any = ...
How do I get the appropriate typeclass instance (at runtime, since we don't know the type statically) and do something with it.
Note that it's inadequate to define a method that literally just gives us the typeclass instance:
def instance(x: Any): Show[_]
Since Show.print requires statically known argument type T we still can't do anything with the result of instance. So really, we need to be able to dynamically dispatch to an already-defined function that uses the instance, such as the following:
def display[T](t: T)(implicit show: Show[T]) = "show: " + show.print(t) + "\n"
So assuming display is defined, how do we invoke display, passing along an appropriate Show instance. I.e. something that invokes display(x) properly.
Miles Sabin accomplishes this here using runtime compilation (Scala eval), as an example of "staging", but with only spare documentation as to what's going on:
https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/staging.scala
Can Miles's approach be put into a library? Also, what are the limitations of this approach e.g. with respect to generic types like Seq[T]?
Part II
Now suppose T is bounded by a sealed type (such that it's possible to enumerate all the sub-types):
trait Show[T <: Foo]
sealed trait Foo
case class Alpha(..) extends Foo
case class Beta(..) extends Foo
In this case, can we do it with a macro instead of runtime compilation? And can this functionality be provided in some library?
I mostly care about Scala 2.12, but it's worth mentioning if a solution works in 2.11 or 2.10.
I'm confused on how Scala's Any relates to java.lang.Object. I know that in scala, AnyRef corresponds to object, but it seems to make a difference whether the method (which takes java.lang.Object) is defined in a java class or a scala class):
the java class:
public class JavaClass {
public static void method(Object input) {
}
}
the scala application:
object ScalaObject extends App{
def method(input:java.lang.Object) = {}
val a:Any = null
method(a) // does not work
JavaClass.method(a) // does work
}
So if the method is in a java-Class, then the compiler allows me to pass a variable of type Any, why is that?
The compiler tries to "make up" for the difference between Scala's and Java's type systems. In Scala, Object =:= AnyRef (they're aliases) and AnyRef <: Any. Therefore, a Scala method that takes Object or AnyRef cannot take an Any or an AnyVal. If you wanted a method that worked on everything, well, then you would have written Any, right?
However, Java methods that take Object are normally meant to work on all values, whether they be actual Objects or primitives (int, long, etc.), and they work due to the boxing conversion of primitives into Objects. Primitives and Object do not have a common supertype like they do in Scala. The Java type system is not expressive enough to differentiate "I only want actual objects," from "I will take anything, be they object or primitive."
Therefore, the Scala compiler patches this up by turning Java methods of Object into methods of Any. This feature is simply to ease interop between the languages. It won't apply this transformation to Scala code though, because if you wanted that behavior then you would have actually written Any instead of Object.
The reason for that is that Any can be either AnyRef or AnyVal, while method can only accept objects which are AnyRef. If you modify the a type to be AnyRef, it is going to work:
def method(input: java.lang.Object) = {}
val a: AnyRef = new Object
method(a)
In case of calling the static Java method, the Scala compiler will turn Any into Object, which also includes boxing of AnyVal values.
I have a value parameterless method that I want to overload with another method employing a higher-kinded type constructor. I also want to make use of the type constructor parameter in the method body. I also want to capture the class tag. This is what I think should be possible:
trait SomeContainer[+A]
trait Foo[+A]
class SomeClass {
// The simple variant
def method[T <: AnyRef]: Foo[T]
// Now the overloaded higher-kinded variant
def method[F[T <: AnyRef : Manifest] <: SomeContainer[T]]: Foo[T] = {
val classTag = manifest[T]
// Do something with it
}
}
However I do not have access to T at all here. The aim here is to make the higher-kinded method here overload the non-higher kinded one def method[T <: AnyRef]: Foo[T]. Have I reached a limitation of the language? Is the non-higher kinded method signature far too open-ended making it impossible for the compiler to disambiguate the one from the other? Is there a better more idiomatic approach to this sort of pattern of overloading on type parameters?
You can't overload methods based only on type parameters at all, since they don't exist in JVM: so far as it's concerned, both methods are def method(): Foo. Technically a compiler could allow it by giving the overloaded methods different names in bytecode, but neither Java nor Scala do so.
Is there a better more idiomatic approach to this sort of pattern of overloading on type parameters?
You could give one of the methods a dummy implicit parameter (there is a DummyImplicit type in Predef for this).
I'm playing around with value classes (class that extends AnyVal) in Scala 2.10.3 but are running into a strange compiler error when using them as parameter to abstract methods.
As the following example demonstrates:
class ValueClass(val x: Int) extends AnyVal
trait Test {
def foo(v: ValueClass): Int
}
new Test {
override def foo(v: ValueClass): Int = 1
}
The compiler spits out the following error:
error: bridge generated for member method foo: (v: ValueClass)Int in anonymous class $anon
which overrides method foo: (v: ValueClass)Int in trait Test
clashes with definition of the member itself;
both have erased type (v: Int)Int
override def foo(v: ValueClass): Int = 1
Why doesn't this work? And is there a way to pass a value class into an abstract method?
So as others noted, this issue has been fixed in later versions. If you are curious at all as to what was changed, I suggest you take a look into this pull request.
SI-6260 Avoid double-def error with lambdas over value classes Post-erasure of value classs in method signatures to the underlying
type wreaks havoc when the erased signature overlaps with the generic
signature from an overriden method. There just isn't room for both.
But we really need both; callers to the interface method will be
passing boxed values that the bridge needs to unbox and pass to the
specific method that accepts unboxed values.
This most commonly turns up with value classes that erase to Object
that are used as the parameter or the return type of an anonymous
function.
This was thought to have been intractable, unless we chose a different
name for the unboxed, specific method in the subclass. But that sounds
like a big task that would require call-site rewriting, ala
specialization.
But there is an important special case in which we don't need to
rewrite call sites. If the class defining the method is anonymous,
there is actually no need for the unboxed method; it will only ever
be called via the generic method.
I came to this realisation when looking at how Java 8 lambdas are
handled. I was expecting bridge methods, but found none. The lambda
body is placed directly in a method exactly matching the generic
signature.
This commit detects the clash between bridge and target, and recovers
for anonymous classes by mangling the name of the target method's
symbol. This is used as the bytecode name. The generic bridge forward
to that, as before, with the requisite box/unbox operations.