From array.scala of scala-2.10.4, The Array is defined as
final class Array[T](_length: Int) extends java.io.Serializable with java.lang.Cloneable {
/** The length of the array */
def length: Int = throw new Error()
def apply(i: Int): T = throw new Error()
def update(i: Int, x: T) { throw new Error() }
override def clone(): Array[T] = throw new Error()
}
Please note, the apply method will throw an exception! And for the accompany object Arrry, I find the following codes:
def apply[T: ClassTag](xs: T*): Array[T] = {
val array = new Array[T](xs.length)
var i = 0
for (x <- xs.iterator) { array(i) = x; i += 1 }
array
}
I know there is an implicit parameter which is ClassTag[T], what make me surprised is how
new Array[T] (xs.length)
is compiled. By decompiling the Array.class, I find that line is translated to :
public <T> Object apply(Seq<T> xs, ClassTag<T> evidence$2)
{
// evidence$2 is implicit parameter
Object array = evidence$2.newArray(xs.length());
...
}
I am really confused by this kind of translation, what is the rule under the hood?
Thanks
Chang
The Scala Array Class is just a fake wrapper for the runtime so you can use arrays in Scala. You're probably confused because those methods on the Array class throw exceptions. The reason they did this is so that if you actually end up using the fake class it blows up since really it should be using the java runtime array, which does not have a proper container class like Scala. You can see how the compiler handles it here. When your using arrays in Scala you're probably also using some implicits from predef like ArrayOps and WrappedArray for extra helper methods.
TLDR: Scala compiler magic makes arrays work with the java runtime under the hood.
On the JVM arrays are exempt from type-erasure, e.g. at runtime instead of Array[_] there is a difference between Array[Int], Array[String] and Array[AnyRef] for example. Unlike Java, Scala can handle this mostly transparently, so
class Foo {
val foo = new Array[Int](123)
}
has a direct byte-code invocation for creating the integer array, whereas
class Bar[A](implicit ev: reflect.ClassTag[A]) {
val bar = new Array[A](123)
}
is solved by using the implicit type evidence parameter of type ClassTag[A] so that at runtime the JVM can still create the correct array. This is translated into the call you saw, ev.newArray(123).
Related
Consider I'm trying to implement delegation by storing properties in a Map instance, and one of the properties delegated is an array:
class Foo private constructor(map: Map<String, Any?>) {
constructor(value: Array<Byte>) : this(mapOf(Foo::value.name to value))
val value: Array<Byte> by map
}
object PropertyDelegationTest {
#JvmStatic
fun main(vararg args: String) {
val foo = Foo(arrayOf(42.toByte(), 127.toByte()))
println(foo.value[0]) // 42
println(foo.value[1]) // 127
}
}
The above compiles just fine and works as expected.
Now consider I want to enhance my property delegation mechanism by implementing a custom Map.getValue(thisRef: Any?, property: KProperty<*>) extension method (overriding the default extension):
import kotlin.reflect.KProperty
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.starProjectedType
import kotlin.reflect.jvm.jvmName
// ...
operator fun <V, V1 : V> Map<in String, V>.getValue(thisRef: Any?, property: KProperty<*>): V1 {
val value = this[property.name]
?: throw NoSuchElementException("Key ${property.name} is missing in the map.")
val clazz = (value as Any)::class
#Suppress("UNCHECKED_CAST")
return when {
clazz.starProjectedType.isSubtypeOf(property.returnType) -> value as V1
else -> throw ClassCastException("${clazz.starProjectedType} (${clazz.jvmName}) cannot be cast to ${property.returnType}")
}
}
This fails at run time:
Exception in thread "main" java.lang.ClassCastException: kotlin.Array<*> ([Ljava.lang.Byte;) cannot be cast to kotlin.Array<kotlin.Byte>
at com.example.PropertyDelegationTestKt.getValue(PropertyDelegationTest.kt:30)
at com.example.Foo.getValue(PropertyDelegationTest.kt)
at com.example.PropertyDelegationTest.main(PropertyDelegationTest.kt:18)
Despite the effective JVM type is known ([Ljava.lang.Byte;), Kotlin-specific run time type of the value is Array<*> while Array<Byte> is required. Consistently, clazz.typeParameters[0].upperBounds[0] evaluates to kotlin.Any?, not kotlin.Byte?.
How do I implement my custom type checking which would also work correctly for arrays? Kotlin version is 1.2.71.
You could remove the explicit type check and instead do a safe cast to V1 and if that fails then throw the exception, e.g.
return value as? V1 ?: throw ClassCastException(...
Is there anyway to create a Scala class which is an object Array , that has an undefined number of objects in the array.
for example I can do what I want using a var
var River1 = new ArrayBuffer[RiverReach]
River1.+=(rr1,rr2,rr3)
and this works fine but i'd like a class so I can add a bunch of methods to it.At the moment I can manually add arguments in the () but the number could vary depending on the Objects. Is there a way to not set a limit? Bit of context I'm a scala beginner and i'm learning via udemy courses at the moment so please bear with me. Any help would be appreciated
Current setup. I've used ArrayBuffer as its mutable and i'll want to sum values from all the elements in the array to the head. But thats a question for a different page.
class River[T>:ArrayBuffer[RiverReach]]() {
//bunch of methods
}
You can wrap the buffer into River, redirect River's += and other methods to the buffer, then add all the other functions you need, for example:
case class RiverBeach(altitude: Int)
class River {
private val buffer = new ListBuffer[RiverBeach]()
def +=(riverBeach: RiverBeach): River = {
buffer += riverBeach
this
}
def ++=(riverBeach: RiverBeach*): River = {
buffer ++= riverBeach
this
}
def size: Int = buffer.size
// your methods
}
val river = new River()
river += RiverBeach(1)
river ++= (RiverBeach(2), RiverBeach(3), RiverBeach(4))
println(river.size) // 4
Mike Allens idea was correct, after more reading better solution is to simply extend Arraybuffer
class River extends Arraybuffer[RiverReach] {
//bunch of methods
}
If have an Array and want to convert it to a ByteArray, how should I go about it? The following for instance fails:
var srcArray = Array<Byte>(10, { 0 })
var tgtArray: ByteArray = srcArray as ByteArray
I do realize though that specialized classes such as ByteArray are:
... not related to the Array class and are compiled down to Java’s primitive arrays for maximum performance.
So, the fact that my approach fails shouldn't surprise me - but what is the canonical way to make the conversion? Simply iterate through srcArray and populate tgtArray one index at a time - or is there a more elegant solution I'm missing?
I don't see any built-in functions apart from the obvious loop-based approach. But you could define an extension function like this yourself:
fun Array<Byte>.toPrimitive(): ByteArray {
val tgtArray: ByteArray = ByteArray(this.size())
for (i in this.indices) {
tgtArray[i] = this[i]
}
return tgtArray
}
fun test() {
val srcArray = Array<Byte>(10, { 0 })
val tgtArray: ByteArray = srcArray.toPrimitive()
}
Kotlin has this in the stdlib as an extension function Array<Byte>.toByteArray()
val srcArray = Array<Byte>(10, { 0 })
val tgtArray = srcArray.toByteArray()
(Note: I changed your var to val which is more common in Kotlin to use read-only values)
You will see similar ones for other primitive data types that have array implementations. You can see them all in the Kotlin documentation for Array extension functions.
How do you define a static extension method in Kotlin? Is this even possible? I currently have an extension method as shown below.
public fun Uber.doMagic(context: Context) {
// ...
}
The above extension can be invoked on an instance.
uberInstance.doMagic(context) // Instance method
but how do I make it static method like shown below.
Uber.doMagic(context) // Static or class method
To achieve Uber.doMagic(context), you can write an extension to the companion object of Uber (the companion object declaration is required):
class Uber {
companion object {}
}
fun Uber.Companion.doMagic(context: Context) { }
This is what the official documentation says:
Kotlin generates static methods for package-level functions. Kotlin
can also generate static methods for functions defined in named
objects or companion objects if you annotate those functions as
#JvmStatic. For example:
Kotlin static methods
class C {
companion object {
#JvmStatic fun foo() {}
fun bar() {}
}
}
Now, foo() is static in Java, while bar() is not:
C.foo(); // works fine
C.bar(); // error: not a static method
I actually had this exact question 30 minutes ago, so I started digging around and couldn't find any solution or workaround for this, BUT while searching I found this section on the Kotlinglang website that states that:
Note that extensions can be defined with a nullable receiver type. Such extensions can be called on an object variable even if its value is null.
So then I had the craziest idea ever, why not define an extension function with a nullable receiver (without actually using that receiver) and then call it on a null object!
So I tried that, and it worked pretty well, but it looked so ugly. It was like this:
(null as Type?).staticFunction(param1, param2)
So I went around that by creating a val in my extensions file of the receiver type that had a value of null and then use it in my other class.
So, as an example, here is how I implemented a "static" extension function for the Navigation class in Android:
In my NavigationExtensions.kt file:
val SNavigation: Navigation? = null
fun Navigation?.createNavigateOnClickListener(#IdRes resId: Int, args: Bundle? = null, navOptions: NavOptions? = null,
navigationExtras: Navigator.Extras? = null) : (View) -> Unit {
//This is just implementation details, don't worry too much about them, just focus on the Navigation? part in the method declaration
return { view: View -> view.navigate(resId, args, navOptions, navigationExtras) }
}
In the code that uses it:
SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)
Obviously, this isn't a class name, it is just a variable of the class type that has a null value. This is obviously ugly on the extension maker side (because they have to create the variable) and on the developer side (because they have to use the SType format instead of the actual class name), but it is the closest that can be achieved right now compared to actual static functions. Hopefully, the Kotlin language makers will respond to the issue that was created and add that feature in the language.
Since I keep coming across this when searching, here's a different approach I haven't seen anyone mention that works in a static way and it works with generics!
Extension definitions:
// Extension function
fun <T> KClass<T>.doSomething() = /* do something */
// Extension Property
val <T> KClass<T>.someVal get() = /* something */
Usage:
MyType::class.doSomething()
MyType::class.someVal
As you can see, the trick is attaching the extension function to the KClass of the type instead since that can be referenced statically.
You can create a static method with using Companion object like:
class Foo {
// ...
companion object {
public fun bar() {
// do anything
}
}
}
and then you can call it like:
class Baz {
// ...
private fun callBar() {
Foo.bar()
}
}
Recomend you to look at this link. As you can see there, you just should declare method at the top-level of the package (file):
package strings
public fun joinToString(...): String { ... }
This is equal to
package strings;
public class JoinKt {
public static String joinToString(...) { ... }
}
With constans everything are the same. This declaration
val UNIX_LINE_SEPARATOR = "\n"
is equal to
public static final String UNIX_LINE_SEPARATOR = "\n";
I also required the ability to extend a Java object with a static method and found the best solution for me was to create a Kotlin object that extended the Java class and add my method there.
object Colour: Color(){
fun parseColor(r: Int?, g: Int?, b: Int?) = parseColor(String.format("#%02x%02x%02x", r, g, b))
}
invocation:
val colour = Colour.parseColor(62, 0, 100)
I'm also quite fond of having the possibility to add static extension methods in Kotlin. As a workaround for now I'm adding the exntension method to multiple classes instead of using one static extension method in all of them.
class Util
fun Util.isDeviceOnline(context: Context): Boolean {
val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = connMgr.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
fun Activity.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }
fun OkHttpClient.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }
To create an extension method in kotlin you have to create a kotlin file(not a class) then declare your method in the file
Eg:
public fun String.toLowercase(){
// **this** is the string object
}
Import the function in the class or file you are working on and use it.
Using Object or * as a type for a Vector doesn't provide generic functionality (like List in Java). Witness:
public static function someGenericVectorUtil (value:Vector.<*>) :void {
// do stuff to/with the Vector
}
var someVector:Vector.<Number>;
someGenericVectorUtil(someVector); // compile-time implicit coercion error
So, perhaps we redefine the utility method to accept an Array. But there's no easy way to convert Vectors going into the utility to Arrays, nor an easy way to pack them back in afterwards, resulting in code like this:
public static function someGenericArrayUtil (value:Array) :void {
// do stuff to/with the formerly-known-as-Vector
}
var someVector:Vector.<Number>;
var tempArray:Array = new Array(someVector.length);
for (var i:uint=0; i<someVector.length; i++) {
tempArray[i] = someVector[i];
}
someGenericVectorUtil(tempArray);
someVector = Vector.<Number>([tempArray]);
Needless to say, that's pretty hideous. Okay, so let's move the Vector-Array-Vector nonsense into a utility:
public static function vectorToArray (Vector.<*>) :Array {
// oh wait....that Vector.<*> param is useless,
// as demonstrated earlier.
}
Any way to straighten out this mess? Or should I just stop using Vectors when I think I might need to run them through generic utilities? (Obviously, also not really much of an option...)
public static function someGenericVectorUtil (value:Vector.<*>) :void {
// do stuff to/with the Vector
}
var someVector:Vector.<Number>;
someGenericVectorUtil(Vector.<*>(someVector));
^ it works. Also try with Array.
This is not an answer but more a long comment to #Lukasz's answer.
The problem with his answer is that you're actually creating a new Vector, so you need to return the Vector from someGenericVectorUtil and re-cast it. E.g. try:
var v:Vector.<int> = Vector.<int>([1,2,3]);
trace( v == Vector.<int>( Vector.<*>( v ) ) ); // traces false
That code just creates a simple Vector of ints, then compares it with a version of itself casted (first to *, then back to int). If you trace the Vectors out, they'll trace identical, but the actual Vectors references themselves aren't the same object. Thus if you have a utility function that modifies the Vector (e.g. a shuffle or randomise function), nothing will change.
E.g:
var v:Vector.<int> = Vector.<int>([1,2,3]);
trace( v ); // traces "1,2,3"
// shuffle() randomises the elements in a vector - this first call won't work
// as the cast creates a new vector
VectorUtil.shuffle( Vector.<*>( v ) );
trace( v ); // traces "1,2,3"
// we need to recast it back, and change shuffle() to return the vector
v = Vector.<int>( VectorUtil.shuffle( Vector.<*>( v ) ) );
trace( v ); // traces "3,1,2"
As you can see, it starts to get a bit ugly towards the end, and if you're keeping track of the Vector anywhere else, you'll need to update the references, but it's the only solution that I've found so far :S