Cannot convert from Object[] to String[]

BlitzMax Forums/BlitzMax Programming/Cannot convert from Object[] to String[]

Czar Flavius(Posted 2010) [#1]
Strict
Local a:Object[3]
a[0] = "hi"
a[1] = "bye"
a[2] = "my"

Local s:String[]
s = String[](a)
For Local b:String = EachIn s
	Print b
Next

It displays nothing but if I change a to String[3] it works fine.


Warpy(Posted 2010) [#2]
The strings "hi", "bye", "my" are getting cast down to Objects when you put them in a. Not all objects can be converted to strings, so blitzmax can't assume when it sees an object that it can convert it to a string.

Now, the way EachIn works is, it iterates through a load of objects given by the enumerated object (in this case, s). It only operates on the ones which can be converted to the type you want (in this case, String). None of the entries in a can do that, because the program only knows they're Objects at this point, so the Print statement is never even encountered.

This behaviour is a bit easier to see with lists:

'create a few different types

'a is the base type
Type Ta
End Type

'b can be converted to a
Type Tb Extends Ta
End Type

'c can be converted to a but not to b
Type Tc Extends Ta
End Type

'make one of each type
l:TList = New TList
l.addlast (New Ta)
l.addlast (New Tb)
l.addlast (New Tc)

'now try iterating through the list with variables of different types
For a:Ta = EachIn l
	Print "an object of type a"
Next

For b:Tb = EachIn l
	Print "an object of type b"
Next

For c:Tc = EachIn l
	Print "an object of type c"
Next


Now, blitzmax should probably throw an error when you try to do what you did with arrays, because everything in an array is of the same type so nothing will ever be able to be cast to the type you want, but because of the way EachIn is implemented that would be very hard.


Czar Flavius(Posted 2010) [#3]
To be more specific, the problem isn't with the EachIn and that was just to test the result. The problem is the conversion process itself - s is Null. I've casted arrays of different objects before so I was disappointed you can't do this with strings.

Here is an example which works.
Strict
Local a:Object[3]
a[0] = TString.Create("hi")
a[1] = TString.Create("bye")
a[2] = TString.Create("my")
Print a.length

Local s:TString[]
s = TString[](a)
Print s.length

For Local b:TString = EachIn s
	Print b.s
Next

Type TString
	Field s:String
	
	Function Create:TString(a:String)
		Local ts:TString = New TString
		ts.s = a
		Return ts
	End Function
End Type



Warpy(Posted 2010) [#4]
oh! Then I look silly.


beanage(Posted 2010) [#5]
I have no Idea why the cast from Object[] to String[] is not working, but why would you have to cast the array, if yo can simply do
Local a:Object[3]
a[0] = TString.Create("hi")
a[1] = TString.Create("bye")
a[2] = TString.Create("my")

For Local s:String = Eachin a ..
? Call me Sherlock if I missed something ..


beanage(Posted 2010) [#6]
Mmmh, I found a rather strange workaround:

If you initialize a with 'New String[3]' it all works:
SuperStrict

Local a:Object[] = New String[3]
a[0] = "hi"
a[1] = "bye"
a[2] = "my"

Local s:String[] = String[](a)
For Local b:String = EachIn s
	Print b
Next


Edit: If you initialize the object array with 'New String[]' You can even set one of the elements to a custom type object and the Object[]->String[] conversion still works out:

SuperStrict

Type something
	Field x:Int
End Type

Local a:Object[] = New String[4]
a[0] = "hi"
a[1] = "bye"
a[2] = "my"
a[3] = New something

Local s:String[] = String[](a)
For Local b:String = EachIn s
	Print b
Next



Warpy(Posted 2010) [#7]
Ok, so the type-checking must have got too hard, but being able to have an array cast down then up is still useful. Look at this:

Type ta
End Type

Type tb Extends ta
	Field s$
	
	Function Create:tb(s$)
		b:tb=New tb
		b.s=s
		Return b
	End Function
End Type

Type tc
End Type

Local a:ta[3]
a[0]=tb.Create("hi")
a[1]=tb.Create("hi")
a[2]=New ta

Local b:tb[]
b=tb[](a)		'allowed, but same problem as with tstring
Print b[2].s	'segfault

Local c:tc[]
c=tc[](a)		'can't convert ta Array to tc Array


The problem must be that strings aren't *really* objects.


beanage(Posted 2010) [#8]
The problem must be that strings aren't *really* objects.

So the question must be "Why arent they *really* objects?". Obviously you can convert a string to an Object, right?

This is actually the one thing I dont like about BlitzMax; the sacrfice of transparency in favor of simplicity..


Czar Flavius(Posted 2010) [#9]
The plot thickens! Is this a feature or a bug? The reason why I asked about this is because I am trying to convert a TList of Strings into a String array, using ToArray(), but it's less hassle to convert it myself.


beanage(Posted 2010) [#10]
I am trying to convert a TList of Strings into a String array, using ToArray()


Surprisingly, looking at what the TList.toArray() Method actually does, this doesnt seem like a good idea:
Local arr:Object[Count()],i
Local link:TLink=_head._succ
While link<>_head
	arr[ i ]=link._value
	link=link._succ
	i:+1
Wend
Return arr

This method iterates the whole list twice; once to count the elements and then to write the actual data. So keep track of the count yourself and avoid using the Count() method too!


Czar Flavius(Posted 2010) [#11]
I noticed that! But it has only a dozen elements at most, so I can live with it for now.