Casting and Operator_Convert

I’m getting into a problem with Operator_Convert:

Defined a method Operator_Convert for a simple class, to serialize it to a JSONItem:

Function Operator_Convert() As JSONItem
  
  dim recipient as new JSONItem
  recipient.Value("user_id") = userID
  recipient.Value("is_read") = isRead
  
  return recipient
  
End Function

this JSONItem need to be part of an array in another JSONItem

so doing this I get an IllegalCastException:

dim n as new MyClass
dim j as new JSONItem
j.append(JSONItem(n))

while doing this it works

dim n as new MyClass
dim j as new JSONItem
j.append(n.Operator_Convert)

this also works

dim n as new MyClass
dim j as new JSONItem
dim tempJSON as JSONItem = n
j.append(n)

Why it’s not possible to cast it to force the Operator_Convert method in a class?

Thats not what casting does
Its more like “treat this as if its one of these” rather than “if you can convert yourself to one of these”
No conversion is done which is what you’d need

Why not just use this which seems the most straight forward & simple & you say works

In fact this doesn’t work, and it’s not what I wrote.
This works:

dim n as new MyClass
dim j as new JSONItem
dim tempJSON as JSONItem = n
j.append(n)

Basically I have to temporarily assign the my class to a JSONItem property to let the Operator_Convert to work.
This is due JSONItem.Append() accept a Variant.

Why use Operator_Convert for this? Operator_Convert is usually used for object creation (as a replacement for New and the constructor). I’d use a method which clearly indicates the creation of an object:

Function Create() As JSONItem dim recipient as new JSONItem recipient.Value("user_id") = userID recipient.Value("is_read") = isRead return recipient End Function
and:

Dim n As New MyClass() Dim j As New JSONItem() j.Append(n.Create)
If the Operator_Convert method is used elsewhere you could redirect the call from Create instead of deleting it:

Function Create() As JSONItem return self.operator_Convert End Function

It’s a matter of syntactic sugar.
I also have for this object an Operator_Convert to create an object from a JSON string.
That way I can write

dim s as string = MyObject dim obj as MyObjectClass = s

[quote=252005:@Massimo Valle]In fact this doesn’t work, and it’s not what I wrote.
This works:

dim n as new MyClass
dim j as new JSONItem
dim tempJSON as JSONItem = n
j.append(n)

Basically I have to temporarily assign the my class to a JSONItem property to let the Operator_Convert to work.
This is due JSONItem.Append() accept a Variant.[/quote]

That makes no sense since you never use tempJSON
So you assign the results of operator_convert to just throw it away
Unless thats not really the code you use

And it wont be whats added to the json item array anyway

The issue you’re likely running into is that jsonItem.Append takes a variant and appends it to a jsonItem ARRAY (not sure thats what you want either)
That wont invoke the operator_convert
It just appends the object directly to the json array

Norman, my code was wrong, sorry.
This is the working one

dim n as new MyClass dim j as new JSONItem dim tempJSON as JSONItem = n j.append(tempJSON)

and it’s the only way, because doing as you said

dim n as new MyClass dim j as new JSONItem j.append(n)

the j object silently append the object n as String, because MyClass has two Operator_Convert, one for converting it to a JSONObject and one for converting it to a String. And it takes the String one.
Doing n.toString I get a JSONException (11) for an Unrecognized object.

I believe the JSONItem.Append should check the object immediately instead of accepting it silently.

Pretty sure it appends the object
When you eventually convert the json to string then the operator_convert to string is invoked

You can confirm this by simply putting a break point in both your operator converts and seeing that

dim n as new MyClass
dim j as new JSONItem
j.append(n) // <<<< you will not get either operator convert invoked here

but if you add

dim s as string = j.ToString

you would get a break on the ToString call

It gets the Operator_Convert As String, just tested.
In fact, when I try to convert the JSONItem to string I get a JSONException with a string reported:

Unrecognized Object: {"user_id":1,"is_read":false}

Huh
I created a small class with just 2 operator converts and those 4 lines
No invocation of either operator convert until the tostring here

if it is then you have something else going on as append takes a variant not a string so there’s no reason for it to invoke the operator_convert

Norman I double checked and yes you are right, the object is appended to the JSONItem.

Now, I believe the JSONItem.Append should only accept JSONItem instead of Variant.
Also even accepting a Variant, it should refuse any object other than JSONItem. What’s the meaning of appending any kind of object here?
In the end, the biggest problem is the JSONItem class silently accept any object, but then it fails when it’s time to serialize the JSONItem to string.

A JSON array can contain other element than just other JSONItems: numbers, strings, etc.

Then it should probably check the appended items are valid.
From the LR: “Values can be any of the following types: Strings, numbers, JSONItems, arrays, Booleans, or Nil.”

Would be nice if JSONItem.Value() would raise an exception if the assigned can’t be used.

Btw, there is still something I don’t understand, doing this:

dim person As New JSONItem person.Value("date") = new Date

I get no error.
Then an exception is raised doing

 dim s as string = person.toString

but the weird thing is the exception converted the date to a string (so it’s potentially a valid value), because it reports:

Exception Message: Unrecognized Object: 2016-03-10 11:02:59 Exception Error Number: 11

Meaning the JSONItem class is either wrong, because it has a string, or if it’s capable to recognize an invalid object assigned, it should complain when the value is assigned.

This means, you have to be aware of what you add. So don’t add a date, add the string representation of a date.

My point is the class should complain earlier about a wrong value or not complain at all
Also if the class has a string for my value, why complain at all, telling me a string is not a valid value?

Again: it is your duty to hand over only valid data types (as in Javascript for example).

Really? A Xojo date object is not a valid value to add to a JSONItem. It has to complain at some point…

Because it is a date object your adding to the JSONItem. There is no conversion done inside the JSONItem class, this is your job. That the debugger is showing it is something not related to a conversion happening. This is a debugger thing, showing a string representation of a date.

You could subclass JSONItem, override Value(name As String, Assigns value As Variant) and set its scope to “Private”. Then add the following methods:

Sub Value(name As String, Assigns value As Integer) Super.Value(name) = value End Sub Value(name As String, Assigns value As Double) Super.Value(name) = value End Sub Value(name As String, Assigns value As Boolean) Super.Value(name) = value End Sub Value(name As String, Assigns value As JSONItem) Super.Value(name) = value End Sub Value(name As String) // Set to null Super.Value(name) = Nil End

Thanks Eli, good suggestion.

Anyway is not the debugger converting it to a string. I copied and pasted from the message box shown from the exception.
This mean the JSONItem doesn’t like to use it to build the JSONString, but gladly convert it to string to show it in the exception message.

Anything that auto converts to string should be valid, no?

Exactly.

Date does not auto convert to string.