I am currently developing a static analysis of Java code using the OPAL framework.
I want to analyze the following Java method:
private void indirectCaller2b(double d, Object o1, Object o2) {
indirectCaller1(d, o1, o2);
}
I know, that indirectCaller2b is only called with the parameters (double, ArrayList, LinkedList).
Having this in mind, I constructed an IndexedSeq of DomainValues, which I pass to the perform-method ob BaseAI.
It looks like this:
Vector({ai.native_methods_parameter_type_approximation.PublicClass, null}[#0;t=101], ADoubleValue, {_ <: java.util.ArrayList, null}[#-4;t=102], {_ <: java.util.LinkedList, null}[#-5;t=103])
The this-parameter ({ai.native_methods_parameter_type_approximation.PublicClass, null}[#0;t=101]) was created with the following code:
domain.TypedValue(0, project.classFile(caller).thisType)
The other domain values were created using the parameterToValueIndex method:
org.opalj.ai.parameterToValueIndex(caller.isStatic, caller.descriptor, index), t)
Here, caller stands for the method indirectCaller2b and t is the known runtime type of the parameter (ArrayList for parameter index 1 and LinkedList for parameter index 2).
When I now perform the abstract interpretation of the method with
BaseAI.perform(classFile, caller, domain)(Some(parameters))
and print the stack index at the program counter, where the call of indirectCaller1 happens with the following code,
for (i <- 0 to analysisResult.operandsArray(pc).size - 1) {
println(s"stack index $i: ${analysisResult.operandsArray(pc)(i)}")
}
I get the following output:
stack index 0: null
stack index 1: {_ <: java.util.LinkedList, null}[#-5;t=103]
stack index 2: ADoubleValue
stack index 3: {ai.native_methods_parameter_type_approximation.PublicClass, null}[#0;t=101]
This is a bit confusing, since I just pass the arguments of indirectCaller2b to indirectCaller1. Therefore, the output should be the same as the IndexedSeq is passed to the perform method.
But in the output, parameter after the double parameter is LinkedList instead of ArrayList. The ArrayList parameter somehow disappeared, and the last parameter on the operandStack is "null".
Can anyone explain me, how this can happen?
Representation of "this"
To get the correct representation for the "this" reference you should use the method
InitializedObjectValue(
origin: ValueOrigin,
objectType: ObjectType ): DomainReferenceValue
to create a representation of the this value. The difference is that in this case the AI will try to use the information that (a) the value is guaranteed to be non-null and is also guaranteed to be initialized. In particular the former property is often interesting and generally leads to more precise results.
Initializing Locals
The function: org.opalj.ai.parameterToValueIndex only calculates the logical origin information (the "pc" that is associated with the value to make it possible to identify the respective values as parameters later on).
To correctly map operands to locals you can either use the method mapOperandsToParameters or you just add all values to an IndexedSeq but add another null value for computational type category 2 values.
Related
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)
I came across this function in Scala def nullable: Boolean = true. I understand what does this function do, but I want to know is there specific name for this kind of function, and what's the motivation not using var
Firstly, I would be very precise in scala: use the word Function to only ever mean an instance of FunctionN and use the word Method when talking about a def (which may have zero or more parameter lists). Secondly, this most definitely does have a body (albeit not enclosed in braces). Its body is the expression true (i.e. a boolean literal).
I assume that you really mean to ask: "why use a method with no parameter lists over a val?"
When deciding whether to represent some property of your class, you can choose between a method and a value (advice: avoid using var). Often, if the property involves no side effects, we can use a def with no parameter lists (the scala idiom is that a def with a single, empty parameter list implies side-effects).
Hence we may choose any of the following, all of which are semantically equivalent at the use-site (except for performance characteristics):
case class Foo(s: String) {
//Eager - we calculate and store the value regardless of whether
// it is ever used
val isEmpty = s.isEmpty
}
case class Foo(s: String) {
//Lazy - we calculate and store the value when it
// it is first used
lazy val isEmpty = s.isEmpty
}
case class Foo(s: String) {
//Non-strict - we calculate the value each time
// it is used
def isEmpty = s.isEmpty
}
Hence we might take the following advice
If the value is computationally expensive to calculate and we are sure we will use it multiple times, use val
If the value is computationally expensive and we may use it zero or many times, use lazy val
If the value is space-expensive and we think it will be generally used a most once, use def
However, there is an additional consideration; using a val (or lazy val) is likely to be of benefit to debugging using an IDE which generally can show you in an inspection window the value of any in-scope vals
The primary difference of the use of def or var/val is the when the value will be executed.
the def defines a name for a value, the value on the right will be executed when it is called (called by name), meaning it is lazy
and var defines a name for a value, and it is execute it's evaluated, eagerly upon definition
Im a Scala newbie and I get that its a really rich language. One thing that is getting me caught out syntax-wise is on function creation. I understand that braces {} are interpreted by the compiler as being synonymous with parentheses () in many contexts, but the following I still do not quite understand.
The following is the output from Scala REPL:
scala> def index = List {}
index: List[Unit]
scala> def index = List ()
index: List[Nothing]
Q1.
If I understand the above correctly, I am creating a function called index that creates a new List (new is omitted because of implicit call to apply method right?).
I see that Unit (equivalent to null in Java?) is the Type of my List when braces {} are used. But Nothing is the type when using parens ().
Q2.
Can someone explain, in simple terms (if possible), the difference between the use of {} and () in creating functions and also what Nothing represents?
Edit - So the following are equivalent?
def index = List {val a = 1; a}
def index = List ({val a = 1; a})
Im also struggling a bit with where the terms function and method seem to be used interchangeably.
Is it correct to say that both the above can both be considered either a function or method?
Or does it depend on who you talk to?
If I understand the above correctly, I am creating a function called index that creates a new List (new is omitted because of implicit call to apply method right?).
(new is omitted because of implicit call to apply method right?)
Yes, kind of. List.apply constructs the List and returns it to your method.
def index = List {} creates a method called index that creates a new List by calling List.apply.
Can someone explain, in simple terms (if possible), the difference between the use of {} and () in creating functions and also what Nothing represents?
The empty curly braces {} represent an anonymous function, rather than a simple list of elements. For example I can do:
scala> def index = List {val a = 1; a}
index: List[Int]
Your method is equivalent to (where the parentheses are omitted):
def index = List({})
The result of the anonymous function is passed to apply. When the braces are empty, the return type of the anonymous function is Unit. So we get List[Unit].
def index = List () always returns an empty List. However, because you have no annotations, the compiler cannot infer a type from this, so it is inferred as Nothing, which is a sub-type of every other type. This allows us to combine a List[Nothing] with a List[Int] and still compile.
I see that Unit (equivalent to null in Java?) ...
Unit is the return type of a method that doesn't return anything. Similar to void in Java, not null.
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.
I have some class C:
class C (...) { ... }
I want to use it to index an efficient map. The most efficient map is an Array.
So I add a "global" "static" counter in companion object to give each object unique id:
object C {
var id_counter = 0
}
In primary constructor of C, with each creation of C I want to
remember global counter value and increase it.
Question 1: How to do it?
Now I can use id in C objects as perfect hash to index array.
But array does not preserve type information like map would, that a given array is indexed by C's id.
Question 2: Is it possible to have it with type safety?
Update:
Type safety in question 2 concerns type of index of map, to avoid mixing two not related ints.
The value of course is (type) safe..
Question 1 asks how to increment a variable in default contructor?
Ie: Where to put?
id_counter += 1
Answer to your question 2:
case class C_Id(val asInt: Int)
object C {
private var list: ArrayBuffer[C]
// resizable array in scala.collection.mutable
// you can also use ArrayList
def apply(id: C_Id) = list(id.asInt) // only accepts an id of C
...
}
class C (...) {
// in constructor:
list += this
}
To edited question 1: The default constructor is just the body of the type, except the definitions of methods and other constructors.
I don't see the problem. I would probably make the counter private so code outside class and object C cannot alter it. Incrementing a var of type Int is trivial:
idCounter += 1
Arrays are type-safe in Scala, since they are implemented directly by JVM arrays (starting in 2.8).
I suspect I've not really understood your questions...
Update:
Increment the counter in the constructor, presumably.
As for creating an actual perfect hash function, I don't think you're really on the right track. (You've just pushed the mapping from whatever your actual keys are into your own code.) You should read up on techniques for creating minimal and / or perfect hash functions.
Could you make the default constructor of C private, and provide a factory method in the companion object (which could easily handle updating the counter)?