You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When declaring objects as private[package/object] or protected[package/object] it is possible to leak out references to these objects into the public api (can be desirable, this in itself is not a problem).
When users of the api receive such private object via a function call, they can create a variable to reference the private object using inferred typing:
val b = getPrivateObject()
However they cannot create such variable using declared typing:
val a: PrivateObject = getPrivateObject()
The line above will generate a compiler error: "class PrivateObject cannot be accessed". Which makes sense, because PrivateObject was declared private. But in this case inferred typing should not work either, otherwise the behaviors of inferred typing and declared typing become inconsistent.
Here is a simplified example that can be tested:
objectObjectHolder {
private[ObjectHolder] classPrivateObjectdefgetPrivateObject=newPrivateObject
}
objectTest {
defmain(args: Array[String]) {
// compiler error: class PrivateObject cannot be accessed// in object test.ObjectHoldervala:ObjectHolder.PrivateObject=ObjectHolder.getPrivateObject
// works finevalb=ObjectHolder.getPrivateObject
println(b.getClass)
}
}
Found on the following platform:[[BR]]
Scala Runtime Version 2.7.30[[BR]]
Netbeans Plugin (Scala Kit), Version 0.15.1
[[BR]]
[[BR]] THE FOLLOWING IS ONLY RELATED IF THE REPORT IS NOT A BUG BUT THE DESIRED BEHAVIOR[[BR]]
If this is a bug, then save your time and skip the rest of the post.
I was completely amazed about scala being flexible enough to create domain specific libraries with domain specific syntax (which is something that no other language to date can offer). If this behavior of inferred typing is desired, it may limit the ability of the programmers to deliver such libraries.
Here is the actual use-case:
To design a simple library that allows the addition of 3d vectors.
answer set a + b + c + d
The obvious route is to override + to do the addition.
However every time there is an addition, you must create a new object. This negatively impact performance. The second obvious choice is to create a method add(arg, store) where arg is the argument and store is the temp location. However using
a add(b, store) add(c, store) add(d, store)
a +(b, store) +(c, store) + (d, store)
is hardly domain specific.
The third obvious choice is to create a temp object on the first addition. Such temp object must be an instance of a different class and behave just like a vector, so the subsequent additions simply accumulate inside the temp vector.
This is nice, since you don't have to create a new instance for every operation, and overall users are not burdened with managing temp variables manually. However if a user can keep a reference to the temp object it becomes very easy to create subtle bugs, as follows:
valanswer=Vec3()
vala=Vec3(1, 1, 1)
valb=Vec3(2, 2, 2)
// t1 and t2 are temp objectsvalt1= a + b // t1 is (3, 3, 3)valt2= t1 + b // t1 eq t2; t1 is (5, 5, 5) - not expected!
answer set t1 + t2
println(answer) // expected (8, 8, 8), got (10, 10, 10)
So the solution is to hide the class of the temp objects by making it package private. If hiding does not work, the api becomes leaky and the solution has to be scrapped.
If visibility rules are enforced you have a domain specific library that is easy to use and efficient.
If the rules are not enforced, you have to chose if you want to deliver something efficient but painful to use or something easy to use but slow. Another option is to think long and hard on how to deliver both. These are not the choices one should face when using a flexible language.
The text was updated successfully, but these errors were encountered:
I have seen this too in macros when trying to lift user-written code into a temporary variable.
Even this simple use-case is something that can come back and bite you:
When declaring objects as private[package/object] or protected[package/object] it is possible to leak out references to these objects into the public api (can be desirable, this in itself is not a problem).
When users of the api receive such private object via a function call, they can create a variable to reference the private object using inferred typing:
val b = getPrivateObject()
However they cannot create such variable using declared typing:
val a: PrivateObject = getPrivateObject()
The line above will generate a compiler error: "class PrivateObject cannot be accessed". Which makes sense, because PrivateObject was declared private. But in this case inferred typing should not work either, otherwise the behaviors of inferred typing and declared typing become inconsistent.
Here is a simplified example that can be tested:
Found on the following platform:[[BR]]
Scala Runtime Version 2.7.30[[BR]]
Netbeans Plugin (Scala Kit), Version 0.15.1
[[BR]]
[[BR]]
THE FOLLOWING IS ONLY RELATED IF THE REPORT IS NOT A BUG BUT THE DESIRED BEHAVIOR[[BR]]
If this is a bug, then save your time and skip the rest of the post.
I was completely amazed about scala being flexible enough to create domain specific libraries with domain specific syntax (which is something that no other language to date can offer). If this behavior of inferred typing is desired, it may limit the ability of the programmers to deliver such libraries.
Here is the actual use-case:
To design a simple library that allows the addition of 3d vectors.
The obvious route is to override + to do the addition.
However every time there is an addition, you must create a new object. This negatively impact performance. The second obvious choice is to create a method add(arg, store) where arg is the argument and store is the temp location. However using
is hardly domain specific.
The third obvious choice is to create a temp object on the first addition. Such temp object must be an instance of a different class and behave just like a vector, so the subsequent additions simply accumulate inside the temp vector.
This is nice, since you don't have to create a new instance for every operation, and overall users are not burdened with managing temp variables manually. However if a user can keep a reference to the temp object it becomes very easy to create subtle bugs, as follows:
So the solution is to hide the class of the temp objects by making it package private. If hiding does not work, the api becomes leaky and the solution has to be scrapped.
If visibility rules are enforced you have a domain specific library that is easy to use and efficient.
If the rules are not enforced, you have to chose if you want to deliver something efficient but painful to use or something easy to use but slow. Another option is to think long and hard on how to deliver both. These are not the choices one should face when using a flexible language.
The text was updated successfully, but these errors were encountered: