Scala generic arrays instantiating - arrays

I have a function that makes Arrays of specific type:
def mkArray[A:ClassTag:Ordering](size:Int):Array[A] = Array.ofDim[A](size)
And I want to make array arr of type Int or String depending on String str like so:
var arr = if(str=="i"){mkArray[Int](size)}else{mkArray[String](size)}
and now I try to add values to the array like so:
arr(n) = num.toInt // num is String like "123"
But it says:
- type mismatch; found : Int required: _366 where type _366 >: Int
with String
How can I get around this, making arr of type Array[Int] or Array[String] depending on string str?
Any help is appreciated,
Thanks!

Scala is a statically typed language, and in your case the type of arr is Array[_ >: Int with String]. Hence, if you give it an Int, you get a type error.
Depending on how you're using the array further in your code, I'd recommend you take a look at Either[1], since it may be helpful in keeping an Array[Either], and processing it using pattern matching differently for when it contains an Int vs String.
[1] http://danielwestheide.com/blog/2013/01/02/the-neophytes-guide-to-scala-part-7-the-either-type.html

Related

Why can't Kotlin implicitly upcast Array of String into Array of Any?

The following code implicitly upcasts a String into Any.
val s = "some string"
val upcasted: Any = s
However, the following does not compile (type mismatch):
val s = arrayOf("some string")
val upcasted: Array<Any> = s
You can successfully cast to Array<Any> as shown:
val s = arrayOf("some string")
val upcasted: Array<Any> = s as Array<Any>
However, this gives the warning "Unchecked cast: Array<String> to Array<Any>".
The same logic does appear to work with Lists, so is the internal implementation of Array incompatible with this type of casting? Perhaps it because of the in-memory representation of Arrays?
You can't safely cast a type to a supertype or subtype like this, because an Array<String> does not qualify as an Array<Any>. If you tried to put a Double in your supposed Array<Any>, it would throw an exception, because the actual type is a String array. Arrays are a special case of generics that don't have type erasure, so they are locked to the type they were instantiated with.
What you could do is cast it to an Array<out Any>, because you can safely use it that way. You can pull Strings out of the array and they qualify as instances of Any. The reverse is not true. You can't put any instance of Any and its subclasses into a String array.
When it comes to List, you can cast it to a List with the supertype type and you don't even have to manually cast it. It's safe so the cast can be done implicitly.
val s = listOf("some string")
val upcasted: List<Any> = s // implicit cast
So why don't you have to cast to List<out Any>? The List interface doesn't have any functions that allow you to add stuff to it. It is defined with an out-projected type in its declaration, so when you type List<Any> it is already the same thing as a List<out Any>
If you try to do this with a MutableList, which accepts putting items into it and is not defined with an out-projected type, then you will run into the same warning as you did with the array.
val s = mutableListOf("some string")
val upcasted: MutableList<Any> = s as MutableList<Any> // warning here and implicit cast impossible
The difference between this and the Array is that there is type-erasure, so you won't have a runtime exception if you try to add some non-String to this list. But there is the possibility of hidden bugs if you are not careful, hence the warning.

Passing swift string to c function char *

I am trying to pass a string argument from swift function wrapper to C function which takes char*.
This a c function
long swe_fixstar2_ut(char* star, double tjd_ut, long iflag, double* xx, char* serr);
The parameter star must provide for at least 41 characters for the returned star name. If a star is found, its name is returned. This function searches the star name from the txt file.
When imported to Swift function looks like this
swe_fixstar_ut(star: UnsafeMutablePointer<Int8>!, tjd_ut: Double, iflag: int32,
xx: UnsafeMutablePointer<Double>!, serr: UnsafeMutablePointer<Int8>!)
I want to achieve something like this
public func sweFixStarsUT(star: String, tjdUT: Double, iFlag: Int32) {
let xx: UnsafeMutablePointer = UnsafeMutablePointer<Double>.allocate(capacity:6)
let serr:UnsafeMutablePointer = UnsafeMutablePointer<CChar>.allocate(capacity:256)
swe_fixstar_ut(star, tjdUT, iFlag, xx, serr)
}
I looked around few of the similar questions but it doesn't solve my problem.
Convert a Swift Array of String to a to a C string array pointer
How to pass an array of Swift strings to a C function taking a char ** parameter
Actually this function comes from Swiss ephemeris C library. Here is the link if you guys are interested to look
https://www.astro.com/swisseph/swephprg.htm#_Toc505244846
As far as I read the doc, the parameter star is used for both in and out, so your star of the Swift function should be inout.
And long is imported as Int, and in Apple's 64-bit platforms, it represents 64-bit signed integer type, if it is actually 32-bit, you may need to update the source files of your C code. I assume it as Int.
So, I would write the bridging code like this:
public func sweFixStarsUT(star: inout String, tjdUT: Double, iFlag: Int) {
let starLen = max(star.utf8.count, 41)
var starBuf: [CChar] = Array(repeating: 0, count: starLen+1)
strcpy(&starBuf, star)
var xx: [Double] = Array(repeating: 0.0, count: 6)
var serr: [CChar] = Array(repeating: 0, count: 256)
swe_fixstar2_ut(&starBuf, tjdUT, iFlag, &xx, &serr)
star = String(cString: starBuf)
}
I prefer using Arrays when passing pointers to a C-function, when the function does not keep the pointers for later use. With using Arrays, you have no need to worry about deallocating.
You can see how the code is converting the input star to an Array of CChar and coverting back the Array into String.
If you find something wrong with this code, please tell me.

Swift 2 - Check Type of empty Array (Introspection)

I'm currently working on introspection in Swift 2 and have Problems getting the specific type for an Array (in this example an Array<String>).
var prop = obj.valueForKey("strings")!
if prop is Array<String> {
println("true")
}
if prop is Array<Int> {
println("true")
}
Output is:
true
true
while it should be
true
false
Is there a way to find out the type for the members of the Array? For example, if I daclared the Array as Array<String> I want to get String or at least be able to check if it is.
MirrorType also did not lead to any success on that by now.
There are 2 ways to achieve what you want:
if prop.dynamicType == Array<Int>.self (or [Int].self) which is better than if prop.dynamicType == [Int]().dynamicType { because [Int]() creates an unused instance of "array of integers".
Typically, when you check if an array is specific-typed, you plan to use it
in a certain way (as a result, you will likely cast your array to
[Int]). Having that said, I recommend using if let arrayOfInts =
prop as? Array<Int> {. Using this construct, you will check for
type compatibility and prepare your array to be treated in a special way (using the casted arrayOfInts reference).
Anyway, it's up to you to decide what to do.
Perhaps what you want is the type of each individual item inside the Array rather than the type of the Array itself? If you are using collection types in Swift, all the items stored in the Array (or Dictionary) are of the same type (except if you declare the Array as Array for example to break the rules... which is not usually necessary, or wanted).
By declaring an Array with its initially values you are automatically telling the compiler what type they are. If you do something like this:
let obj = [1,2,3]
var property = obj[0]
if property is String {
print("true")
}
if property is Int {
print("true")
}
The compiler will already tell you that property is String always fails, and there is actually no need to do that test (because we already know that it will always fail).
If you are working with Objective-C APIs and types on the other hand, there may be occasions where you will need to test for type, this is a good example of testing for type in an Objective-C collection that has items of different types:
let userDefaults = NSUserDefaults.standardUserDefaults()
let lastRefreshDate: AnyObject? = userDefaults.objectForKey("LastRefreshDate")
if let date = lastRefreshDate as? NSDate {
print("\(date.timeIntervalSinceReferenceDate)")
}
Hope this helps.

Typed Array assignment in F#

Why doesn't this work?
open System
let ary = Array.create<Int16> 10
ary.[0] <- 42 // compiler error
printfn "%d" ary.[0] // compiler error
The error I get is something like:
The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints
The signature for Array.create<'T> is:
Array.create : int -> 'T -> 'T []
Currently you're only providing the first argument (number of elements to create) so ary is actually a function: Int16 -> Int16 []
You need to pass the second argument which is the value to use for the elements in the array:
let ary = Array.create<Int16> 10 0s
If you want the type's default value to be used for all the elements in the array (as it is in the above example) then you can use Array.zeroCreate as #Sehnsucht has pointed out

defining a new array of a specific type on F#

How can I specifically define a new array of a specific type T ?
Strangely, I couldn't find any helpful information about it..
I want to write something like this:
let arr = new Array()
only that the elements of arr must be of type T.
How can I do it on F# ?
If type of elements is unknown, you can use explicit type annotation:
let arrayOfTenZeroes = Array.zeroCreate<int> 10
let emptyIntArray: int array = [||]
When you use high-order functions from Array module, you don't have to do so since type of elements is automatically inferred by the type checker:
// arr is inferred as int array
let arr = Array.init 10 (fun i -> i+1)
Maybe the Array.init<'T> and Array.create<'T> functions are what you are looking for.
Also consider using a Sequence instead of an array.
A sequence is a logical series of elements all of one type. Sequences are particularly useful when you have a large, ordered collection of data but do not necessarily expect to use all the elements.
Perhaps you can try something like this.
let myStringArray : string array = Array.zeroCreate 10
let myIntArray : int array = Array.zeroCreate 10
let myCharArray : char array = Array.zeroCreate 10
It's described on msdn.
Automatic generalization and type inference are great features you should take advantage of.
When an array is created:
let arr = Array.zeroCreate 10
its type is generalized. In this case it's inferred to be 'T[] (as general as possible).
Once you do something like:
let x = arr.[0] + 1
or
printfn "%s" arr.[0]
it can infer the concrete type (int[] or string[], respectively).
The lack of explicit types makes your code much cleaner. Save type annotations for when they're truly needed.

Resources