Basically, I want to store arrays of distinct object types generically (so, in Variants) and retrieve them elsewhere into an Object array.
Firstly, if I cast an concrete array into an abstract one (i.e., in an Object array) and back, it won’t work, but if I store the abstract in a variant, then back, it works.
Secondly, the same thing upside-down - concrete into variant and then into abstract - is not working.
I hope following snippet shows, what I want to do:
Dim concrete(), concreteBack() As Dictionary
Dim abstract() As Object = concrete
abstract.Append(new Dictionary("a" : "b"))
'concreteBack = abstract 'this line won't compile
Dim temp As Variant = abstract
concreteBack = temp
'abstract = temp 'this line raises an TypeMismatchException
MsgBox(concrete(0).Value("a") + ", " + concreteBack(0).Value("a"))
Is there anyone who can explain me why the out commented lines are not working?
Or how I can tell the compiler, that in line 4 ‘abstract’ has the right type?
I have a workaround in mind, where i define a container which stores an object array and a variant, but i’d prefer it to manage ALL types in a single variant and this is, I believe, the idea behind variants.
The reason that variant works is that it does run-time type checking and the variables just happen to be the right type. The commented lines use compile-time type checking and they aren’t the right type of variables (although they could hold the right type, but you would have to cast the generic variable to the specific one, which I don’t know if there is a syntax for that that works with arrays).
Be careful with arrays and variants, however. You can get yourself twisted into knots very easily. What you’re trying to do will probably require introspection at some point.
In general I avoid trying to use Xojo as a dynamically typed language
Interfaces, classes & subclasses make it so the compiler can help me out a lot more
With variants & such it can’t except somewhat superficially
concrete is an array of dictionaries
abstract is an array of objects
… of course you can’t assign an array of dictionaries to a variable dimmed as array of objects and vice versa. You will have to fill the abstract array by looping over the concrete one and appending each element to abstract.
b = a //upcasting works
a = b //downcasting not[/code]
The down casting method I use relies on upcasting to the parameter type to make it generic
Sub downCast(src() As Object, dest() As Object)
if src = nil or dest = nil then return
dim last As integer = src.Ubound
for i As integer = 0 to last
dest(i) = src(i)
I’m still curious what you even want to use this style of code for ?
Every time I run into this sort of thing I really have to examine it and rethink doing this in a type safe way usually using a class that is a strongly typed container type and some strongly typed element type (even if it uses interfaces which makes it more flexible)
Since there’s no STL in Xojo (too bad but we need generics for it) you have to make your own types but then you get type safety just like if you used STL in C++
I want to serialize objects, primitives and their array forms, transfer them via network and deserialize them. So I wrote something, that expects a Variant, examines its type, gets the value out of it, serzializes it and so on. It works for everything, even for primitive arrays, but not for object arrays.
I COULD make a super class, called ‘Serializable’ or something, but that would be overhead at multiple points
Or, the other way, is to use Object() arrays instead of distinct ones from beginning on, inserting my objects into them, store them in the variant and retrieve them as Object arrays. I think I will go this way now, since I do not have endless time for this project, but it is at first more intuitive and faster if you have a method like
Sub method(myObjects() As MyClass)
for each mo As MyClass In myObjects
Sub method(myObjects() As Object)
Dim mo As MyClass
for i As Integer to UBound(myObjects)
mo = MyClass(myObjects(i))
AND you have to document it somewhere that you can (MUST) cast each object before you can use it.
And I still can’t get, why it is not possible to downcast. As far as I understood, array variables are references.
So, if I copy the reference to an array of a specific class to an array of a super class (yeah, it works for each superclass, not only for Objects), it implicitly converts it, and everything is fine.
That the compiler denounces the opposite direction, is apparantly correct, because variables (and array elements) of super classes are not necessarily instances of my specific subclass. So, with simple variables, Xojo kindly gives me the option to cast:
Dim foo As New MyClass
Dim bar As Object = foo
foo = MyClass(bar)
and I am happy. But this won’t work:
Dim foo() As New MyClass
Dim bar() As Object = foo
foo = MyClass()(bar) 'no
foo = Array(MyClass)(bar) 'no
foo = MyClasses(bar) 'no
foo = IamSureThisIsAnArrayOfMyClasses(bar) 'no
The same exact thing, except they are no arrays, does not work, since Xojo has no syntax to cast arrays
[quote=83948:@Christopher Kobusch]I want to serialize objects, primitives and their array forms, transfer them via network and deserialize them. So I wrote something, that expects a Variant, examines its type, gets the value out of it, serzializes it and so on. It works for everything, even for primitive arrays, but not for object arrays.
I COULD make a super class, called ‘Serializable’ or something, but that would be overhead at multiple points[/quote]
Thats what I’d do as then every object type you want to do this with implements the interface
But you’ll have to have every class you implement implement the interface as there really isn’t (seriously) a way to do a generic object serializer - really
Yeah, didn’t with everybody else, it really isn’t possible. When developing the first WE, I spent tried hard to find a generic way to serialize and unserialize any object. Even had some secret (evil) tricks at my disposal. Just wasn’t going to happen.
It’s a rabbit hole. You’ll solve one problem and create / discover two more. Stop while you’re ahead and use something like JSONItem instead.