In order to avoid Java exceptions I'm using Scala's exception handling class.
However, when compiling the following snippet:
import scala.util.control.Exception._
val cls = classManifest[T].erasure
// Invoke special constructor if it's available. Otherwise use default constructor.
allCatch opt cls.getConstructor(classOf[Project]) match {
case Some(con) =>
con.newInstance(project) // use constructor with one Project param
case None =>
cls.newInstance // just use default constructor
};
I receive the following error:
error: type mismatch;
[scalac] found : java.lang.reflect.Constructor[_]
[scalac] required: java.lang.reflect.Constructor[_$1(in method init)] where
type _$1(in method init)
[scalac] allCatch opt cls.getConstructor(classOf[Project]) match {
[scalac] ^
[scalac] one error found
What's going on here and how can I fix it?
I have no explanation, but a much shorter example which I hope pinpoint where the problem occurs. I think it is not related at all to exceptions, nor to reflection. Whether this behavior is an arcane but correct consequence of the specification or a bug, I have no idea.
val untypedList : List[_] = List("a", "b")
val typedList : List[String] = List("a", "b")
def uselessByName[A](a: => A) = a
def uselessByValue[A](a: A) = a
uselessByName(untypedList) fails with the same error as your code. The other combinations do not. So combination of a method with a generic call-by-name argument, called with a parameter of a generic with an existential type.
uselessByName[List[_]](untypedList) works, so I guess if you call explicitly opt[Constructor[_]] it might work too.
The type inference scheme has gotten confused by the types available--specifically, by the type of cls. If we write generic code:
def clser[A](cls: Class[A]) = allCatch opt cls.getConstructor(classOf[Project])
then it works perfectly okay. But you're probably doing something else--I can't tell what because you didn't provide the code--and this results in a mismatch between the expected and actual types.
My currently solution is to cast the constructor explicitly.
cls.getConstructor(classOf[Project]) becomes cls.getConstructor(classOf[Project]).asInstanceOf[Constructor[Project]].
I'm still wondering about the actual error and if there are better ways to resolve it -- so I'm going to leave this open.
Related
Can anyone help me to understand how "read" macro is implemented? I have the feeling that "do_read" function below is actually called, but could not figure out how that is done. I'm intrigued by the "SourceInfoTransform" class. Can anyone give me a hint on its usage?
The "SyncReadMem" implementation is listed below.
Thanks in advance for any help!
Best regards,
-Fei
sealed class SyncReadMem[T <: Data] private (t: T, n: BigInt, val readUnderWrite: SyncReadMem.ReadUnderWrite) extends MemBase[T](t, n) {
def read(x: UInt, en: Bool): T = macro SourceInfoTransform.xEnArg
/** #group SourceInfoTransformMacro */
def do_read(addr: UInt, enable: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
val a = Wire(UInt())
a := DontCare
var port: Option[T] = None
when (enable) {
a := addr
port = Some(read(a))
}
port.get
}
}
The SourceInfoTransform is a scala macro that transforms the def read into the def do_read. The code for the macro is in src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala of github.com/chipsalliance/chisel3. In that file there are a lot of transform classes for handling different chisel constructs with different numbers of arguments. The main use of the SourceInfoTransform is to get the line number of the Chisel/Scala source so it can be reported in Exceptions and in generated Firrtl and Verilog. Here is an article on macros, there are many more available.
Good luck.
Chick's answer is mostly correct--it's correct on the "how" and where to look, but slightly wrong on the "why":
The main use of the SourceInfoTransform is to get the line number of the Chisel/Scala source
This is not quite true, you can get source locators with merely having implicit sourceInfo: SourceInfo, and you could have that on the original def read if you wanted to. What the SourceInfoTransform macros do is resolve ambiguity when you want to do a bit extraction immediately following invoking the read method, eg.
myMem.read(addr, en)(16, 0)
If we had defined read with the implicits directly, the compiler would think you're trying to pass 16 and 0 as the implicit arguments, when in reality, you're trying to call .apply on the resulting T (if it's a subtype of Bits). The macro resolves the ambiguity so that the compiler knowns you're not trying to pass the implicits.
Here's a link to a talk where I describe this (warning while the little part about source locators and the macro are correct, much of this talk is out-of-date): https://youtu.be/2-ZiXNd9wbc?t=2756
I am seeing some strange (un)boxing behaviour in Scala I cannot explain.
Consider the following code:
case class SomeCaseClass(longOpt: Option[Long])
def someMethod(l: Long): Unit = ???
val x: SomeCaseClass = // Case class populated from JSON in some code I do not control
x.longOpt.map(l => someMethod(l))
The attempt to call someMethod yields the following error:
java.lang.ClassCastException java.lang.Integer cannot be cast to java.lang.Long
at scala.runtime.BoxesRuntime.unboxToLong(BoxesRuntime: 105)
Running the following:
x.longOpt.map(_.getClass).get
yields long
Obviously the conversion of JSON to the case class is the prime suspect but I would expect a runtime error instantiating the case class if the value was not of the correct type.
Can anyone explain what is happening here?
Obviously the conversion of JSON to the case class is the prime suspect but I would expect a runtime error instantiating the case class if the value was not of the correct type.
I want to understand why Scala does not complain when the case class is created, only when I attempt to manipulate the Option[Long] which it would appear does not contain a Long at all...
I guess the thing is in type erasure. For
case class SomeCaseClass(longOpt: Option[Long])
Option[Long] is just Option[_] at runtime. So there is no ClassCastException during instantiating the case class because it's not casting Option[Integer] to Option[Long], it's Option[_] to Option[_].
And when you work with the content of Option it's ClassCastException because you try to cast Integer to Long.
I get a compiler error like this:
The type definitions for type '<ExceptionType>' in the signature and implementation are not compatible because the signature requires that the type supports the interface System.Collections.IStructuralEquatable but the interface has not been implemented
I narrowed it down to the fact that my exception's record type contains a field of a function type.
In my real code, I can work around this because I don't need this function in the exception, but I'm still curious, why do I get this error only when I have a signature file and how would I have my exception implement IStructuralEquatable?
Here's my signature file, Test.fsi:
module Test
type exception_type
exception TestException of exception_type
val throw_test_exception: unit -> unit
Here's my implementation file, Test.fs:
module Test
type exception_type = { value: unit -> unit }
exception TestException of exception_type
let throw_test_exception (): unit =
let r = { value = (fun () -> ()) }
raise (TestException r)
When there's no signature file, everything compiles just fine.
For your signature to work you need to define the full type of exception_type in your signature:
test.fsi
module Test
type exception_type = { value: unit -> unit }
...
Then the error will go away.
Signature files are typically not created by hand.. You can create them using the --sig option.
I'm not sure why would you want to pass a function in an exception. This does not make sense to me but if you elaborate your case (in another question), maybe I might be able to offer some suggestions.
I'm stuck with a simple problem: I have a java.util.Optional and want to use the orElseThrow method to throw an exception if value is not present. However I cannot figure the right syntax to do this in Xtend. In Java, I would do:
Optional<String> host = ... // get from some method
host.orElseThrow(() -> new IllegalArgumentException("Host is not provided"));
But this does not compile in Xtend. The error message in Eclipse is like this (where MyClass is the name of my custom class):
Multiple markers at this line
- Type mismatch: cannot convert from Pair<MyClass, IllegalArgumentException> to Supplier<? extends Throwable>
- no viable alternative at input ')'
Please help!
Try something like:
val Optional<String> host = ... // get from some method
host.orElseThrow[new IllegalArgumentException("Host is not provided")]
See the documentation about lambda expressions.
(-> is an operator in Xtend but it is not related to lambda expressions. See the documentation about operators and search for the Pair Operator.)
I am not sure if I am missing something here. I would like to compare two classes that uses the same interface. Is this possible? I understand that the is operator compares classes, but is there any similar function when you use interfaces?
// works
var effect1 : CrazyEffect = new CrazyEffect();
var effect2 : SaneEffect = new SaneEffect();
trace(effect1 is effect2) // false
// does not work
var effect1 : ISoundEffect = new CrazyEffect();
var effect2 : ISoundEffect = new SaneEffect();
trace(effect1 is effect2)
1067: Implicit coercion of a value of type ISoundEffect to an unrelated type Class.
Note the differences between concepts of a class and of an object. The former is a data type whereas the latter is a runtime instance of it, a variable. is operator can not compare one variable to another.
According to language reference
is Operator
Evaluates whether an object is compatible with a specific data type,
class, or interface. Use the is operator instead of the instanceof
operator for type comparisons. You can also use the is operator to
check whether an object implements an interface.
In other words, compiler expects the first operand to be a variable whereas the second operand should be a type identifier.
var sample:String = "Object is an instance of a class.";
^^^ ^^^
variable type identifier
However effect2 is not a type identifier but a variable. Hence the error message.
Unfortunately there is no generic operator to test for interface commonality. The only alternative is:
trace((s is ISoundEffect) && (t is ISoundEffect));
Update
Checking whether objects are instances of a same class can be done by comparing class names:
if (getQualifiedClassName(effect1) == getQualifiedClassName(effect2)) {
// true
}
For in depth discussion see Get the class used to create an object instance in AS3
Even though it will work with getQualifiedClassName, there's a better method to check whether two objects are instances of the same class:
a['constructor'] === b['constructor']
getQualifiedClassName is very slow and CPU intensive. Since the above code just compares property values it is lightning fast. And yes, constructor IS a property of every object, however FB will complain if you try to access it using dot-notation, that's why I use dynamic property access.