Can I convert a FieldValue to a DomainValue in OPAL? - scala

I am writing a static analysis using the OPAL framework.
Therefore, I invoke an abstract interpretation of a method, where I have upper type bounds for the passed parameters as FieldTypes.
It looks like this:
BaseAI.perform(classFile, caller, domain)(parameters)
Where parameters is an IndexedSeq[FieldType].
This results in the following type error:
type mismatch; found : scala.collection.immutable.IndexedSeq[org.opalj.br.FieldType] required: Option[scala.collection.IndexedSeq[domain.DomainValue]] (which expands to) Option[scala.collection.IndexedSeq[domain.Value]]
Is there any possibility to convert my FieldTypes to DomainValues?
Can I use
domain.ClassValue(origin, identifiedFieldType)
to convert it, even if the type is e.g. an int? (since int is not a class)
If yes, is there a method, which computes the origin index for method parameters?

Part one of the question:
You can use:
domain.TypedValue(origin, parameterType)
In this case parameterType can be "any type".
Part two of the question:
The following function defined by the package object org.opalj.ai can be used compute the correct value index.
def parameterToValueIndex(
isStaticMethod: Boolean,
descriptor: MethodDescriptor,
parameterIndex: Int
): Int = {

Related

new to scala anyone explain the code for me?

def indexOf[T](seq: Seq[T],value: T, from: Int):Int={
for(i<-from until seq.length){
if(seq(i)== value) return i
}
-1
}
Anyone explain to me indexOf[T] meaning? And what does (seq:Seq[T],value:T) do?
def indexOf - This is a method. We'll call it indexOf.
[T] - This method will make reference to an unspecified type. We'll call it T.
(seq:Seq[T], value:T, from:Int) - This method will take 3 passed parameters:
variable seq which is a Seq of elements of type T
variable value which is a single value of type T
variable from which is a single value of type Int
:Int - This method returns a value of type Int.
= { - Mehod code begins here.
This is related to Scala generics.
https://docs.scala-lang.org/tour/generic-classes.html
In simple terms, here, T acts as a place holder for any data type.
The indexOf function takes a generic T, which during runtime can be a Integer, String or custom Employee object.
For example in the sequence, you can pass a Seq of Employee or String and same data type value.
By using generics, for your example, you dont have to create different indexOf function for every other data type.
How to call indexOf? As below:
val index = indexOf[String](stringSeq, "searchThis", 0)
or
val index = indexOf[Employee](employeeSeq, empObj, 0)
This method is what we call a parametric method in scala.
Parametric methods in Scala can be parameterized by type as well as
value. The syntax is similar to that of generic classes. Type
parameters are enclosed in square brackets, while value parameters are
enclosed in parentheses.
Since T is a generic type, that means that indexOf method can be called on a variety of types.
Your method indexOf[T] takes a type parameter T and value parameters seq, value and from.
When calling your method, you can either set explicitly the type you will be manipulating by replacing the T by your concrete type (see example 1), or let the compiler work for you (type inference) based on the parameter type of your param seq and value. (see example 2)
Example 1
val index = indexOf[Int](Seq(3, 5, 4), 4, 0)
Example 2
val index = indexOf(Seq("alice", "bob", "yo"), "bob", 1)

Scala Compile Error

I have trouble in building the following code:
type graph_t = scala.collection.mutable.Map[Long, (Long, Float)];
var graph : graph_t = graph_t();
However, it does work by replacing the graph_t() with the original type:
var graph : graph_t = scala.collection.mutable.Map[Long, (Long, Float)] ();
Any answer will be appreciated.
Scala knows two namespaces: types and values. Types define what values are capable of, and values are the things you call methods on.
graph_t() is a method call (the apply method), but you did not define a value called graph_t, you defined a type called graph_t, and you cannot call methods on types.
The reason scala.collection.mutable.Map[Long, (Long, Float)] () works is because scala.collection.mutable.Map is both a type and a value.
That's interesting. Try this:
type s = String;
var x = s()
You get the same error: not found.
That's is because the name of the class is both the name of the type and the name of the constructor, but the name of a type is not necessarily the name of a constructor.
In this case, the function Map actually constructs a concrete implementation of the Map abstract class.

How do I get an object's type and pass it along to asInstanceOf in Scala?

I have a Scala class that reads formatting information from a JOSN template file, and data from a different file. The goal is to format as a JSON object specified by the template file. I'm getting the layout working, but now I want to set the type of my output to the type in my template (i.e. if I have a field value as a String in the template, it should be a string in the output, even if it's an integer in the raw data).
Basically, I'm looking for a quick and easy way of doing something like:
output = dataValue.asInstanceOf[templateValue.getClass]
That line gives me an error that type getClass is not a member of Any. But I haven't been able to find any other member or method that gives me an variable type at runtime. Is this possible, and if so, how?
Clarification
I should add, by this point in my code, I know I'm dealing with just a key/value pair. What I'd like is the value's type.
Specifically, given the JSON template below, I want the name to be cast to a String, age to be cast to an integer, and salary to be cast a decimal on output regardless of how it appears in the raw data file (it could be all strings, age and salary could both be ints, etc.). What I was hoping for is a simple cast that didn't require me to do pattern matching to handle each data type specifically.
Example template:
people: [{
name: "value",
age: 0,
salary: 0.00
}]
Type parameters must be known at compile time (type symbols), and templateValue.getClass is just a plain value (of type Class), so it cannot be used as type parameter.
What to do instead - this depends on your goal, which isn't yet clear to me... but it may look like
output = someMethod(dataValue, templateValue.getClass),
and inside that method you may do different computations depending on second argument of type Class.
How do I get an object's type and pass it along to asInstanceOf in Scala?
The method scala.reflect.api.JavaUniverse.typeOf[T] requires it's type argument to be hard-coded by the caller or type-inferred. To type-infer, create a utility method like the following (works for all types, even generics - it counteracts java runtime type arg erasure by augmenting T during compilation with type tag metadata):
// http://www.scala-lang.org/api/current/index.html#scala.reflect.runtime.package
import scala.reflect.runtime.universe._
def getType[T: TypeTag](a: T): Type = typeOf[T]
3 requirements here:
type arg implements TypeTag (but previous implementation via Manifest still available...)
one or more input args are typed T
return type is Type (if you want the result to be used externally to the method)
You can invoke without specifying T (it's type-inferred):
import scala.reflect.runtime.universe._
def getType[T: TypeTag](a: T): Type = typeOf[T]
val ls = List[Int](1,2,3)
println(getType(ls)) // prints List[Int]
However, asInstanceOf will only cast the type to a (binary consistent) type in the hierarchy with no conversion of data or format. i.e. the data must already be in the correct binary format - so that won't solve your problem.
Data Conversion
A few methods convert between Integers and Strings:
// defined in scala.Any:
123.toString // gives "123"
// implicitly defined for java.lang.String via scala.collection.immutable.StringOps:
123.toHexString // gives "7b"
123.toOctalString // gives "173"
"%d".format(123) // also gives "123"
"%5d".format(123) // gives " 123"
"%05d".format(123) // gives "00123"
"%01.2f".format(123.456789) // gives "123.46"
"%01.2f".format(123.456789) // gives "0.46"
// implicitly defined for java.lang.String via scala.collection.immutable.StringOps:
" 123".toInt // gives 123
"00123".toInt // gives 123
"00123.4600".toDouble // gives 123.46
".46".toDouble // gives 0.46
Parsing directly from file to target type (no cast or convert):
Unfortunately, scala doesn't have a method to read the next token in a stream as an integer/float/short/boolean/etc. But you can do this by obtaining a java FileInputStream, wrapping it in a DataInputStream and then calling readInt, readFloat, readShort, readBoolean, etc.
In a type-level context the value-level terms still have a few accessors. The first one and the one you asked for is the type of the value itself (type):
output = dataValue.asInstanceOf[templateValue.type]
if the type of the value has inner members, those become available as well:
class A {
class B {}
}
val a: A = new A
val b: a.B = new a.B
Notice b: a.B.
I must also mention how to access such members without a value-level term:
val b: A#B = new a.B

How should Scala default arguments to refer to a previous positional argument?

Scala-lang reference 5.5.1 and 6.6.1 gave me the impression that a default parameter would be able to refer to a previously evaluated one:
class Test(val first: String, val second: String = first)
but from experimenting it seems the only way to do this is to use the form:
class Test(val first: String)(val second: String = first)
and then define an auxiliary constructor or a creational companion class to avoid specifying the second set of brackets when creating. I don't really understand how this second constructor works, it looks like a curried function so I might guess that it is necessary to evaluate first independently of second, is this correct? Is this form necessary or is there some syntatic sugar I can use to tweak the first constructor into doing what I want?
As Travis Brown points out, you can indeed only refer to a previous argument in a default expression when it is from a previous argument list (so you do need to currify).
Now, regarding your particular use case, default arguments and method overloading are sometimes two ways of achieving the same thing.
I think the simplest solution to your scenario is simply to define Test as follows:
class Test(val first : String, val second : String) {
def this(f : String) = this(f, f)
}
If you want to make it more complicated, an alternative way, using a companion object:
class Test(val first : String)(val second : String = first)
object Test {
def apply(f : String) = new Test(f)
def apply(f : String, s : String) = new Test(f)(s)
}
(A small difference is that now you create objects without new.)
What you cannot do, is define it as:
class Test(val first : String)(val second : String = first) {
def this(f : String, s : String) = this(f)(s)
}
...because the curried version gets translated into (among other things) a method with the same signature as the overloaded contructor.
From 5.3 of the spec:
The scope of a formal value parameter includes all subsequent
parameter sections and the template t.
Regular methods are the same, by the way (from 4.6):
The scope of a formal value parameter name x comprises all
subsequent parameter clauses, as well as the method return type and
the function body, if they are given.
I.e., whether you've got a constructor or an ordinary method, a value parameter name isn't in scope in its own parameter clause. In your second version the constructor has two parameter clauses, and first is only in scope in the second. See 5.3 for more detail about multiple parameter clauses.

Scala - mapping a list of integers to a method that receives java.lang.Object

Working in Scala-IDE, I have a Java library, in which one of the methods receives java.lang.Object. And I want to map a list of Int values to it. The only solution that works is:
val listOfInts = groupOfObjects.map(_.getNeededInt)
for(int <- listOfInts) libraryObject.libraryMethod(int)
while the following one:
groupOfObjects.map(_.getNeededInt).map(libraryMethod(_)
and even
val listOfInts = groupOfObjects.map(_.getNeededInt)
val result = listOfInts.map(libraryObject.libraryMethod(_))
say
type mismatch; found : Int required: java.lang.Object Note: an
implicit exists from scala.Int => java.lang.Integer, but methods
inherited from Object are rendered ambiguous. This is to avoid a
blanket implicit which would convert any scala.Int to any AnyRef. You
may wish to use a type ascription: x: java.lang.Integer.
and something like
val result = listOfInts.map(libraryObject.libraryMethod(x => x.toInt))
or
val result = listOfInts.map(libraryObject.libraryMethod(_.toInt))
does not work also.
1) Why is it happening? As far as I know, the for and map routines do not differ that much!
2) Also: what means You may wish to use a type ascription: x: java.lang.Integer? How would I do that? I tried designating the type explicitly, like x: Int => x.toInt, but that is too erroneus. So what is the "type ascription"?
UPDATE:
The solution proposed by T.Grottker, adds to it. The error that I am getting with it is this:
missing parameter type for expanded function ((x$3) => x$3.asInstanceOf[java.lang.Object])
missing parameter type for expanded function ((x$3) => x$3.asInstanceOf{#null#}[java.lang.Object]{#null#}) {#null#}
and I'm like, OMG, it just grows! Who can explain what all these <null> things mean here? I just want to know the truth. (NOTE: I had to replace <> brakets with # because the SO engine cut out the whole thing then, so use your imagination to replace them back).
The type mismatch tells you exactly the problem: you can convert to java.lang.Integer but not to java.lang.Object. So tell it you want to ask for an Integer somewhere along the way. For example:
groupOfObjects.map(_.getNeededInt: java.lang.Integer).map(libraryObject.libraryMethod(_))
(The notation value: Type--when used outside of the declaration of a val or var or parameter method--means to view value as that type, if possible; value either needs to be a subclass of Type, or there needs to be an implicit conversion that can convert value into something of the appropriate type.)