Operator_Convert firing with nil parameter

Consider this code:

dim o as OrmDate = someDate

OrmDate is a Date subclass that implements Operator_Convert(Date). All it does is call Constructor(Date), and that all works fine, unless someDate is nil. In that case, I want o to be nil too, but I don’t see how I can do that.

First, is the behavior I’m seeing intended or a bug? Second, is there any way for Operator_Convert to abort without raising an exception? In other words, how can I get the behavior I want?

[quote=329037:@Kem Tekinay]Consider this code:

dim o as OrmDate = someDate

OrmDate is a Date subclass that implements Operator_Convert(Date). All it does is call Constructor(Date), and that all works fine, unless someDate is nil. In that case, I want o to be nil too, but I don’t see how I can do that.
[/quote]
You cant

Intended AFAIK

Not that I know of

You cant

Recall that Operator_convert is more like an “initializer” than an “allocator”
But the time it is called the instance is created and the operator_convert is your opportunity ti convert some data and initialize this instance from that data
But you cannot change the fact the instance has been created

Mars and I had this discussion ages ago on the old forums (maybe the old NUG)

Thanks.

I’m going to file this as a bug anyway because I can’t think of a situation where you would want to “convert” from nil.

Moving this to General.

oh I can but then the object is basically a proxy and knowing that is was set with nil is important

Say you have object wrappers for data types (like Java does for “Integer” which wraps an integer)
Very handy for database stuff since you now have a way to represent an integer column that has a nil value

But with the change I’m proposing, that would still work, no?

dim o as IntegerObject = rs.Field( "int_column" ).Value
// if the column is nil, o is nil

No because now I would have a nil object not an object that contains a nil
Big difference

Imagine some ORM code that created these objects (as I described)
Then at some point you could see if any contained a nil (since it might have an instance method like “IsNil”)
And that some time in the future you wanted to put a value IN that object so it was no longer “nil”
You have to change your code to check for nil objects and create the right one at that point

Objects that can exist but contain nil is a useful design in lots of places

I see that, but I don’t think that’s the usual case.

No matter, since it would change behavior, perhaps there is another solution. What comes to mind immediately is an additional form of Operator_Convert:

Function Operator_Convert (o As Object) As MyClass
  if o is nil then
    return nil
  else
    // Do some stuff with o
    return self
  end if
End Function

That would solve my problem without disturbing existing code. Thoughts?

[quote=329048:@Kem Tekinay]I see that, but I don’t think that’s the usual case.
[/quote]
Well not YOUR use case but there are several places where people have asked about exactly this
https://forum.xojo.com/conversations/all?search=nullable

[quote=329048:@Kem Tekinay]
No matter, since it would change behavior, perhaps there is another solution. What comes to mind immediately is an additional form of Operator_Convert:

Function Operator_Convert (o As Object) As MyClass
  if o is nil then
    return nil
  else
    // Do some stuff with o
    return self
  end if
End Function

That would solve my problem without disturbing existing code. Thoughts?[/quote]
Not sure it does

Because… ?

Because I’m not sure it does what you expect or fixes the problem

I might be misunderstanding. I’m proposing an additional form of Operator_Convert that does not currently exist, one that will let me control exactly what is assigned when used. If the input is nil, I can return nil and the variable I’m assigning it to will be nil.

What have I missed?

Ah well that would explain why I’m not sure it would fix it
It wasnt that clear you were proposing a new operator convert form
It looks a lot to the “Convert TO” forms that already exist
Obviously I misread your post

Not sure I’d call this “operator_convert” though as this would have to have entirely different semantics

Currently operator_convert behaves more like a constructor + setter code (an initializer as it were)
But note neither of those allocate an instance
Thats done before your code is called (constructor or operator_convert)

This one is more like an allocator and decides whether to allocate an instance or not
And thats sufficiently different that I’d call it “something else”
And of course then everything has to know to call this if it exists

That seems a very big change

I’d just design your stuff so it can be nullable and move on since the FR is unlikely to happen ASAP (or soon enough for your immediate needs)

My immediate needs were solved by switching to a factory method, so I’m thinking long term now.

Thanks for your thoughts.

Almost what you want is something along the lines of

Function Operator_Allocate (o As Object) As boolean
  if o is nil then
    return false // do not allocate an object and leave the caller "nil"
  else
    return true // do allocate an object & call whatever other operator_convert / constructor methods 
                // need to be called after allocating an object and initially setting it up
  end if
End Function

Havent though about the ramifications of this (or whether it would even be actually entertained)

As Norman has pointed out there is no way.

What I did for accessing databases was to introduce a different API to the built-in one. This API consist of three parts for each data type:
– A replacement for Nil
– A replacement for the built-in Variant methods to access values from DatabaseField
– A replacement for the bind method for PreparedStatement

This is the simplified code for Int64 as an example:

[code]Module Integers

// Used for sorting Nil values before or after non-Nil values when sorting arrays of Int64
Private Property mNilsLast As Boolean

Global Function NilInteger() As Int64
// Use the maximum and the minimum Int64 values as placeholders for Nil
Return If(mNilsLast, 9223372036854775807, -9223372036854775807)
End

// The next two methods look weird, but the Extends on Int64 allow for this code: Int64.SortNilsLast = …

Global Sub SortNilsLast(Extends i As Int64, Assigns value As Boolean)
mNilsLast = value
End

Global Function SortNilsLast(Extends i As Int64) As Boolean
Return mNilsLast
End

// To be used instead of Int64Value
Global Function AsInteger(Extends dbf As DatabaseField) as Int64
Return If(dbf.Value Is Nil, NilInteger, dbf.Int64Value)
End

// To be used instead of the built-in Bind method
Global Sub BindInteger(Extends ps As MySQLPreparedStatement, index As Integer, value As Int64)
If value = NilInteger Then
ps.BindType(index, MySQLPreparedStatement.MYSQL_TYPE_NULL)
ps.Bind(index, Nil)
Else
ps.BindType(index, MySQLPreparedStatement.MYSQL_TYPE_LONGLONG)
ps.Bind(index, value)
End
End

End Module[/code]

And this is how to use it:

[code]Dim rst As RecordSet = someDatabase.SQLSelect(“SELECT * FROM someTable;”)

Dim someField() As Int64

Do Until rst.EOF
someField.Append rst.Field(“someField”).AsInteger // Never use Int64Value here, as Nil would become Zero
End

If someField(0) = NilInteger Then // Comparing to Nil would not compile
// someField is Nil
Else
// someField is not Nil
End

// Array holds: 4, NilInteger, 16, 1, 3, NilInteger, NilInteger, 2, 9, 6, …

someField.Sort()

// Array holds now : NilInteger, NilInteger, NilInteger, 1, 2, 3, 4, 9, 16, …

Int64.SortNilsLast = True
someField.Sort()

// Array holds now : 1, 2, 3, 4, 9, 16, …, NilInteger, NilInteger, NilInteger[/code]

I have these kind of modules for Date, Double, Int64, Text. For Boolean database values I have a class Trilean which can hold the values NilTrilean, False, True (internally stored as Integer with the values -1 = NilTrilean, 0 = False, 1 = True, 2 = NilTrilean).

The advantages of all that is that you use the internal data types, which doesn’t slow down the application. Introducing wrapper classes showed to be two slow when handling large amounts of data.