www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - NULL indicator in Variant

reply Steve Teale <steve.teale britseyeview.com> writes:
How big a deal would it be to add a NULL indicator to the VariantN struct.

I use the term NULL as opposed to null deliberately. Variant already 
provides the hasValue() method, which can serve as a null indicator. But 
in using it as a parameter in database modules, it would be useful to be 
able to give a Variant instance a type, as in v = "", but also to set it 
explicitly as NULL with setNull() or whatever.

Could this fly without breaking existing code?

Steve
Oct 27 2011
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 27.10.2011 17:12, Steve Teale wrote:
 How big a deal would it be to add a NULL indicator to the VariantN struct.

 I use the term NULL as opposed to null deliberately. Variant already
 provides the hasValue() method, which can serve as a null indicator. But
 in using it as a parameter in database modules, it would be useful to be
 able to give a Variant instance a type, as in v = "", but also to set it
 explicitly as NULL with setNull() or whatever.

 Could this fly without breaking existing code?

 Steve

Surely Variant.init should do the trick? -- Dmitry Olshansky
Oct 27 2011
next sibling parent reply Steve Teale <steve.teale britseyeview.com> writes:
 
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve
Oct 27 2011
parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.e. int.init and so on. - Alex
Oct 27 2011
parent simendsjo <simendsjo gmail.com> writes:
On 29.10.2011 04:04, Steven Schveighoffer wrote:
 I don't like Variant having this behavior when it's only of specific
 use.  Variant is not a database-only type.

 Here's another idea:

 struct DBNull(T) { }

 Where T is the type for the column.  i.e.:

 row.column = DBNull!int;

 Now, you have your flag indicating it's null (you should be able to
 write a function that returns whether the column is null or not), it
 doesn't consume any more space (value is already part of a union that's
 bigger than DBNull!int), and the type of field is still valid.

This is basically what ADO.Net does: http://msdn.microsoft.com/en-us/library/system.dbnull.aspx
Oct 29 2011
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 27 Oct 2011 10:16:26 -0400, Alex Rønne Petersen <xtzgzorex gmail.com>
wrote:
 On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.e. int.init and so on. - Alex

Init is a built-in property of all types and for Variant (both new and old) setting a variant to its init will cause it to have no value.
Oct 27 2011
prev sibling next sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Thu, 27 Oct 2011 16:16:26 +0200, Alex Rønne Petersen wrote:

 On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.e. int.init and so on. - Alex

Same catch 22. In order to have an init property, the Variant would have to have been set to some type, at which point hasValue() would say yes. Steve
Oct 27 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 27 Oct 2011 12:58:57 -0400, Steve Teale  =

<steve.teale britseyeview.com> wrote:

 On Thu, 27 Oct 2011 16:16:26 +0200, Alex R=C3=B8nne Petersen wrote:

 On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.e. int.init and so on. - Alex

Same catch 22. In order to have an init property, the Variant would ha=

 to have been set to some type, at which point hasValue() would say yes=

 Steve

import std.variant; void main() { Variant v =3D 1; assert(v.hasValue()); v =3D v.init; assert(!v.hasValue()); } -Steve
Oct 27 2011
prev sibling next sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Thu, 27 Oct 2011 13:09:43 -0400, Steven Schveighoffer wrote:

 On Thu, 27 Oct 2011 12:58:57 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 
 On Thu, 27 Oct 2011 16:16:26 +0200, Alex Rønne Petersen wrote:

 On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.e. int.init and so on. - Alex

Same catch 22. In order to have an init property, the Variant would have to have been set to some type, at which point hasValue() would say yes. Steve

import std.variant; void main() { Variant v = 1; assert(v.hasValue()); v = v.init; assert(!v.hasValue()); } -Steve

Exactly, and v has reverted to being typeless: import std.variant; import std.stdio; void main() { Variant v = 1; assert(v.hasValue()); v = v.init; assert(!v.hasValue()); writeln(v.type.toString()); } Steve
Oct 27 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 27 Oct 2011 13:53:02 -0400, Steve Teale  =

<steve.teale britseyeview.com> wrote:

 On Thu, 27 Oct 2011 13:09:43 -0400, Steven Schveighoffer wrote:

 On Thu, 27 Oct 2011 12:58:57 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:

 On Thu, 27 Oct 2011 16:16:26 +0200, Alex R=C3=B8nne Petersen wrote:

 On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.e.=




 int.init and so on.

 - Alex

Same catch 22. In order to have an init property, the Variant would have to have been set to some type, at which point hasValue() would =



 yes.

 Steve

import std.variant; void main() { Variant v =3D 1; assert(v.hasValue()); v =3D v.init; assert(!v.hasValue()); } -Steve

Exactly, and v has reverted to being typeless:

Sorry to jump in mid-stream, but you seemed to be suggesting Variant = didn't have an init without an assigned type. Why wouldn't you just wrap variant if you want to introduce a nullable = variant type? Why does Variant have to be muddied with requirements for= = database API? Database null is an entirely different animal from D's nu= ll. -Steve
Oct 27 2011
prev sibling next sibling parent reply Steve Teale <steve.teale britseyeview.com> writes:
On Thu, 27 Oct 2011 13:58:54 -0400, Steven Schveighoffer wrote:

 On Thu, 27 Oct 2011 13:53:02 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 
 On Thu, 27 Oct 2011 13:09:43 -0400, Steven Schveighoffer wrote:

 On Thu, 27 Oct 2011 12:58:57 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:

 On Thu, 27 Oct 2011 16:16:26 +0200, Alex Rønne Petersen wrote:

 On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.e. int.init and so on. - Alex

Same catch 22. In order to have an init property, the Variant would have to have been set to some type, at which point hasValue() would say yes. Steve

import std.variant; void main() { Variant v = 1; assert(v.hasValue()); v = v.init; assert(!v.hasValue()); } -Steve

Exactly, and v has reverted to being typeless:

Sorry to jump in mid-stream, but you seemed to be suggesting Variant didn't have an init without an assigned type.

No, I was just saying it didn't help.
 Why wouldn't you just wrap variant if you want to introduce a nullable
 variant type?  Why does Variant have to be muddied with requirements for
 database API?  Database null is an entirely different animal from D's
 null.

Well, yes, that was my first reaction, but I thought I'd ask - if there was a spare bit somewhere in Variant, would it do much harm, and Variant is getting a makeover. Maybe there are circumstances other than database interactions where it could be useful. Steve
Oct 27 2011
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, October 28, 2011 19:04 Steven Schveighoffer wrote:
 I don't like Variant having this behavior when it's only of specific use.
 Variant is not a database-only type.

Agreed. Unless such a change has a real use case beyond databases, I do not think that it should be built into Variant. - Jonathan M Davis
Oct 28 2011
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 27 Oct 2011 14:06:47 -0400, Steve Teale <steve.teale britseyeview.com>
wrote:
 On Thu, 27 Oct 2011 13:58:54 -0400, Steven Schveighoffer wrote:
 On Thu, 27 Oct 2011 13:53:02 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 On Thu, 27 Oct 2011 13:09:43 -0400, Steven Schveighoffer wrote:
 On Thu, 27 Oct 2011 12:58:57 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 On Thu, 27 Oct 2011 16:16:26 +0200, Alex Rønne Petersen wrote:
 On 27-10-2011 15:50, Steve Teale wrote:






[snip]
 Well, yes, that was my first reaction, but I thought I'd ask - if there
 was a spare bit somewhere in Variant, would it do much harm, and Variant
 is getting a makeover. Maybe there are circumstances other than database
 interactions where it could be useful.

 Steve

Speaking as the one making over variant, let me see if I understand your use case. Similar to typecons.Nullable, you want to be able to test any type for isNull and be to 'nullify' any type. Correct? Does nullifying a value wipe it clean? i.e. can you ever un-nullify something? If you assign to a nulled variant, should there be some sort of special behavior? Should 'hasValue' return false or true? If true, what should 'get' & company return? 'type' should return the TypeInfo of the type that was nullified, correct? What should 'toString' return? One thing that concerns me is the API. The new Variant supports reflection via opDispatch, so adding 'isNull' and 'nullify' members would, for example, block Nullable!int's 'isNull' and 'nullify' members. Would '__isNull' '__nullify' be acceptable? Alternatively, I could special case opAssign and opEquals: 'var = Variant.NULL' and 'var == Variant.NULL'. Thoughts? Sorry for all the questions, but I want to make sure what I build is what you need. That said, I'm petty sure I can incorporate what you want.
Oct 27 2011
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Thu, 27 Oct 2011 19:06:47 +0100, Steve Teale  
<steve.teale britseyeview.com> wrote:
 On Thu, 27 Oct 2011 13:58:54 -0400, Steven Schveighoffer wrote:
 Why wouldn't you just wrap variant if you want to introduce a nullable
 variant type?  Why does Variant have to be muddied with requirements for
 database API?  Database null is an entirely different animal from D's
 null.

Well, yes, that was my first reaction, but I thought I'd ask - if there was a spare bit somewhere in Variant, would it do much harm, and Variant is getting a makeover. Maybe there are circumstances other than database interactions where it could be useful.

Could you wrap std.typecons.Nullable around it? It's currently disabled, but a quick copy/paste into my own src, plus templating the opAssign e.g. /** Assigns $(D value) to the internally-held state. */ void opAssign(T value) { enforce(_value); *_value = value; } and this works: import std.exception; //nullable import std.variant; import std.stdio; void main() { Nullable!Variant a; assert(a.isNull); a = 5; assert(!a.isNull); assert(a == 5); } I believe Nullable is going to be re-enabled soon? One argument in the nullable pull request: https://github.com/D-Programming-Language/phobos/pull/153 which also applies, is; why not just use Variant*'s in your database cases? R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Oct 28 2011
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Fri, 28 Oct 2011 10:23:03 +0100, Regan Heath <regan netmail.co.nz>  
wrote:

 On Thu, 27 Oct 2011 19:06:47 +0100, Steve Teale  
 <steve.teale britseyeview.com> wrote:
 On Thu, 27 Oct 2011 13:58:54 -0400, Steven Schveighoffer wrote:
 Why wouldn't you just wrap variant if you want to introduce a nullable
 variant type?  Why does Variant have to be muddied with requirements  
 for
 database API?  Database null is an entirely different animal from D's
 null.

Well, yes, that was my first reaction, but I thought I'd ask - if there was a spare bit somewhere in Variant, would it do much harm, and Variant is getting a makeover. Maybe there are circumstances other than database interactions where it could be useful.

Could you wrap std.typecons.Nullable around it? It's currently disabled, but a quick copy/paste into my own src, plus templating the opAssign e.g. /** Assigns $(D value) to the internally-held state. */ void opAssign(T value) { enforce(_value); *_value = value; }

err.. sorry, I meant: /** Assigns $(D value) to the internally-held state. If the assignment succeeds, $(D this) becomes non-null. */ void opAssign(T)(T value) { _value = value; _isNull = false; } :p R
Oct 28 2011
prev sibling next sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Fri, 28 Oct 2011 00:35:45 -0400, Robert Jacques wrote:

 On Thu, 27 Oct 2011 14:06:47 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 On Thu, 27 Oct 2011 13:58:54 -0400, Steven Schveighoffer wrote:
 On Thu, 27 Oct 2011 13:53:02 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 On Thu, 27 Oct 2011 13:09:43 -0400, Steven Schveighoffer wrote:
 On Thu, 27 Oct 2011 12:58:57 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 On Thu, 27 Oct 2011 16:16:26 +0200, Alex Rønne Petersen wrote:
 On 27-10-2011 15:50, Steve Teale wrote:






[snip]
 Well, yes, that was my first reaction, but I thought I'd ask - if there
 was a spare bit somewhere in Variant, would it do much harm, and
 Variant is getting a makeover. Maybe there are circumstances other than
 database interactions where it could be useful.

 Steve

Speaking as the one making over variant, let me see if I understand your use case. Similar to typecons.Nullable, you want to be able to test any type for isNull and be to 'nullify' any type. Correct?

I want to be able to mark a Variant which is otherwise functional and representing a type. It might have the .init value for the type, or it could have any other value. The mark in my context would signify that it should be treated as a NULL for database purposes. But it could be used to add any other subtlety to a variant. It's just a mark I think.
 
 Does nullifying a value wipe it clean? i.e. can you ever un-nullify
 something?

No, it's just a mark, you can wipe it off and it then reverts to being a perfectly normal variant
 If you assign to a nulled variant, should there be some sort of special
 behavior?

I think maybe it should wipe the mark. If I've chosen a particular variant in a particular state to mark, then I'd say the mark would lose its significance if the thing was radically changed.
 Should 'hasValue' return false or true? If true, what should 'get' &
 company return?

I think hasValue() et al should behave as usual - after all, it's just a mark. It's what I choose to do with the value from get or whatever that should be influenced.
 'type' should return the TypeInfo of the type that was nullified,
 correct

Absolutely - that's the primary requirement for me. That the variant should carry its type information, but not necessarily have a useful value.
 What should 'toString' return?
 

Following my current path, it should return what it would normally return.
 One thing that concerns me is the API. The new Variant supports
 reflection via opDispatch, so adding 'isNull' and 'nullify' members
 would, for example, block Nullable!int's 'isNull' and 'nullify' members.
 Would '__isNull' '__nullify' be acceptable? Alternatively, I could
 special case opAssign and opEquals: 'var = Variant.NULL' and 'var ==
 Variant.NULL'. Thoughts?

Avoid the word null - use mark or whatever. If adding it means earmarking more than a single bit, then make it 'flags'. That way the facility is quite general-purpose. I think that in a 'type' that is supposed to stand for almost anything, this is not out of place.
 Sorry for all the questions, but I want to make sure what I build is
 what you need. That said, I'm pretty sure I can incorporate what you
 want.

Questions are good. Do my answers make any sense? Steve
Oct 28 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 27 Oct 2011 14:06:47 -0400, Steve Teale  =

<steve.teale britseyeview.com> wrote:

 On Thu, 27 Oct 2011 13:58:54 -0400, Steven Schveighoffer wrote:

 On Thu, 27 Oct 2011 13:53:02 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:

 On Thu, 27 Oct 2011 13:09:43 -0400, Steven Schveighoffer wrote:

 On Thu, 27 Oct 2011 12:58:57 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:

 On Thu, 27 Oct 2011 16:16:26 +0200, Alex R=C3=B8nne Petersen wrote=





 On 27-10-2011 15:50, Steve Teale wrote:
 Surely Variant.init should do the trick?

Dmitry, Are you talking about the new std.variant - I don't see 'init' currently. Steve

He is probably referring to the 'init' property on the *type*, i.=






 int.init and so on.

 - Alex

Same catch 22. In order to have an init property, the Variant woul=





 have to have been set to some type, at which point hasValue() woul=





 say yes.

 Steve

import std.variant; void main() { Variant v =3D 1; assert(v.hasValue()); v =3D v.init; assert(!v.hasValue()); } -Steve

Exactly, and v has reverted to being typeless:

Sorry to jump in mid-stream, but you seemed to be suggesting Variant didn't have an init without an assigned type.

No, I was just saying it didn't help.
 Why wouldn't you just wrap variant if you want to introduce a nullabl=


 variant type?  Why does Variant have to be muddied with requirements =


 database API?  Database null is an entirely different animal from D's=


 null.

Well, yes, that was my first reaction, but I thought I'd ask - if ther=

 was a spare bit somewhere in Variant, would it do much harm, and Varia=

 is getting a makeover. Maybe there are circumstances other than databa=

 interactions where it could be useful.

I don't like Variant having this behavior when it's only of specific use= . = Variant is not a database-only type. Here's another idea: struct DBNull(T) { } Where T is the type for the column. i.e.: row.column =3D DBNull!int; Now, you have your flag indicating it's null (you should be able to writ= e = a function that returns whether the column is null or not), it doesn't = consume any more space (value is already part of a union that's bigger = than DBNull!int), and the type of field is still valid. -Steve
Oct 28 2011
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 28 Oct 2011 10:22:37 -0400, Steve Teale <steve.teale britseyeview.com>
wrote:
 On Fri, 28 Oct 2011 00:35:45 -0400, Robert Jacques wrote:

[snip]
 Speaking as the one making over variant, let me see if I understand your
 use case. Similar to typecons.Nullable, you want to be able to test any
 type for isNull and be to 'nullify' any type. Correct?

I want to be able to mark a Variant which is otherwise functional and representing a type. It might have the .init value for the type, or it could have any other value. The mark in my context would signify that it should be treated as a NULL for database purposes. But it could be used to add any other subtlety to a variant. It's just a mark I think.
 Does nullifying a value wipe it clean? i.e. can you ever un-nullify
 something?

No, it's just a mark, you can wipe it off and it then reverts to being a perfectly normal variant

Okay, I think there was a bit of mis-communication here. What I'm asking is if the following represents required functionality: Variant var = 1; assert(var == 1); var.nullify; assert(var.isNull); var.unnullify; assert(var == 1); That is, do you need to be able to recover the previous value of the variant once it has been nulled?
 If you assign to a nulled variant, should there be some sort of special
 behavior?

I think maybe it should wipe the mark. If I've chosen a particular variant in a particular state to mark, then I'd say the mark would lose its significance if the thing was radically changed.

So would the following be correct behavior? Variant var = 1; assert(var == 1); var.nullify; assert(var.isNull); var = "Hello"; assert(var == "Hello"); assert(var.isNull == false);
 Should 'hasValue' return false or true? If true, what should 'get' &
 company return?

I think hasValue() et al should behave as usual - after all, it's just a mark. It's what I choose to do with the value from get or whatever that should be influenced.

As far as I understand it, a database null means that the field has no value. If a nulled variant has no value what does 'get' return? And whatever it does return, how can that be logically correct?
 'type' should return the TypeInfo of the type that was nullified,
 correct

Absolutely - that's the primary requirement for me. That the variant should carry its type information, but not necessarily have a useful value.

If variant does 'not necessarily have a useful value', why should 'hasValue' et al. function as if there were a value?
 What should 'toString' return?

Following my current path, it should return what it would normally return.

So Variant var = 5; var.nullify; assert(var.toString == "5"); and not assert(var.toString == "Nulled int"; ?
 One thing that concerns me is the API. The new Variant supports
 reflection via opDispatch, so adding 'isNull' and 'nullify' members
 would, for example, block Nullable!int's 'isNull' and 'nullify' members.
 Would '__isNull' '__nullify' be acceptable? Alternatively, I could
 special case opAssign and opEquals: 'var = Variant.NULL' and 'var ==
 Variant.NULL'. Thoughts?

Avoid the word null - use mark or whatever. If adding it means earmarking more than a single bit, then make it 'flags'. That way the facility is quite general-purpose. I think that in a 'type' that is supposed to stand for almost anything, this is not out of place.
 Sorry for all the questions, but I want to make sure what I build is
 what you need. That said, I'm pretty sure I can incorporate what you
 want.

Questions are good. Do my answers make any sense?

Yes, but your answers weren't for the questions I was asking. Each of your answers appears to be predicated on a particular solution you wish to used to solve your problem. I've tried to ask clarifying questions to help define your actual use cases and functional needs. What I'm trying to define is the minimal feature set you need to make databases work well, not the behavior of the implementation you envision.
Oct 28 2011
prev sibling next sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Fri, 28 Oct 2011 23:50:37 -0400, Robert Jacques wrote:

 On Fri, 28 Oct 2011 10:22:37 -0400, Steve Teale
 <steve.teale britseyeview.com> wrote:
 On Fri, 28 Oct 2011 00:35:45 -0400, Robert Jacques wrote:

[snip]
 Speaking as the one making over variant, let me see if I understand
 your use case. Similar to typecons.Nullable, you want to be able to
 test any type for isNull and be to 'nullify' any type. Correct?

I want to be able to mark a Variant which is otherwise functional and representing a type. It might have the .init value for the type, or it could have any other value. The mark in my context would signify that it should be treated as a NULL for database purposes. But it could be used to add any other subtlety to a variant. It's just a mark I think.
 Does nullifying a value wipe it clean? i.e. can you ever un-nullify
 something?

No, it's just a mark, you can wipe it off and it then reverts to being a perfectly normal variant

Okay, I think there was a bit of mis-communication here. What I'm asking is if the following represents required functionality: Variant var = 1; assert(var == 1); var.nullify; assert(var.isNull); var.unnullify; assert(var == 1); That is, do you need to be able to recover the previous value of the variant once it has been nulled?
 If you assign to a nulled variant, should there be some sort of
 special behavior?

variant in a particular state to mark, then I'd say the mark would lose its significance if the thing was radically changed.

So would the following be correct behavior? Variant var = 1; assert(var == 1); var.nullify; assert(var.isNull); var = "Hello"; assert(var == "Hello"); assert(var.isNull == false);
 Should 'hasValue' return false or true? If true, what should 'get' &
 company return?

I think hasValue() et al should behave as usual - after all, it's just a mark. It's what I choose to do with the value from get or whatever that should be influenced.

As far as I understand it, a database null means that the field has no value. If a nulled variant has no value what does 'get' return? And whatever it does return, how can that be logically correct?
 'type' should return the TypeInfo of the type that was nullified,
 correct

Absolutely - that's the primary requirement for me. That the variant should carry its type information, but not necessarily have a useful value.

If variant does 'not necessarily have a useful value', why should 'hasValue' et al. function as if there were a value?
 What should 'toString' return?

return.

So Variant var = 5; var.nullify; assert(var.toString == "5"); and not assert(var.toString == "Nulled int"; ?
 One thing that concerns me is the API. The new Variant supports
 reflection via opDispatch, so adding 'isNull' and 'nullify' members
 would, for example, block Nullable!int's 'isNull' and 'nullify'
 members. Would '__isNull' '__nullify' be acceptable? Alternatively, I
 could special case opAssign and opEquals: 'var = Variant.NULL' and
 'var == Variant.NULL'. Thoughts?

Avoid the word null - use mark or whatever. If adding it means earmarking more than a single bit, then make it 'flags'. That way the facility is quite general-purpose. I think that in a 'type' that is supposed to stand for almost anything, this is not out of place.
 Sorry for all the questions, but I want to make sure what I build is
 what you need. That said, I'm pretty sure I can incorporate what you
 want.

Questions are good. Do my answers make any sense?

Yes, but your answers weren't for the questions I was asking. Each of your answers appears to be predicated on a particular solution you wish to used to solve your problem. I've tried to ask clarifying questions to help define your actual use cases and functional needs. What I'm trying to define is the minimal feature set you need to make databases work well, not the behavior of the implementation you envision.

Robert, I read through my answers again, and they seem to me to be perfectly valid responses to your questions. It's just that you are insisting on the use of terms like nullify and isNull that have different semantics than what is actually needed to deal with the database situation. Yes, I know I used NULL in my original question, but I was at pains to back of from that in my responses to your questions. I believe all that's needed to make variants play well with databases is a mark or flag. This could be used in other contexts for quite unrelated purposes. For the database case it would essentially serve as an ignore- this-value-just-note-the-type flag. It is not essential, but it would make a database interface using variants easier to code and to use. Probably we should just forget the idea. Steve
Oct 29 2011
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 29 Oct 2011 16:23:11 -0400, Steve Teale <steve.teale britseyeview.com>
wrote:
 On Fri, 28 Oct 2011 23:50:37 -0400, Robert Jacques wrote:

[snip]
 I read through my answers again, and they seem to me to be perfectly
 valid responses to your questions. It's just that you are insisting on
 the use of terms like nullify and isNull that have different semantics
 than what is actually needed to deal with the database situation. Yes, I
 know I used NULL in my original question, but I was at pains to back of
 from that in my responses to your questions.

 I believe all that's needed to make variants play well with databases is
 a mark or flag. This could be used in other contexts for quite unrelated
 purposes. For the database case it would essentially serve as an ignore-
 this-value-just-note-the-type flag.

Steve, when you state: "For the database case it would essentially serve as an ignore-this-value-just-note-the-type flag", you are no longer describing your concept or use case, you are describing how you would implement that use case using functionality X. From what I can tell, you're thinking of an implementation like this: Variant var = 1; var.mark = true; if(var.mark) { // Do DB NULL stuff } else { // Do DB value stuff } But how is that different from this: Variant var = 1; var.nullify; if(var.isNull) { // Do DB NULL stuff } else { // Do DB value stuff } or this: auto var = Variant.NULL!int; if(var.hasValue) { // Do DB NULL stuff } else { // Do DB value stuff } or this: auto var = typeid(int); if(auto type = var.peek!TypeInfo) { // Do DB NULL stuff } else { // Do DB value stuff } ? I don't care about adding functionality X; you can already build a null-able DB type on top of Variant (see above, or use Nullable!Vairant, etc). I care about making variant (or Algebraic) _into_ a null-able DB type. So that it composes integrates well with the rest of our code-bases.
 It is not essential, but it would make a database interface using
 variants easier to code and to use. Probably we should just forget the
 idea.

 Steve

Databases and their ilk are a pretty big and important use case. So I think cleanly supporting them is necessary. That said, there are lots of alternatives available.
Oct 29 2011
prev sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Sat, 29 Oct 2011 17:42:54 -0400, Robert Jacques wrote:
 
 Variant var = 1;
 var.mark = true;
 
 if(var.mark) {
      // Do DB NULL stuff
 } else {
      // Do DB value stuff
 }
 
 But how is that different from this:
 
 Variant var = 1;
 var.nullify;
 
 if(var.isNull) {
      // Do DB NULL stuff
 } else {
      // Do DB value stuff
 }
 
 or this:
 
 auto var = Variant.NULL!int;
 
 if(var.hasValue) {
      // Do DB NULL stuff
 } else {
      // Do DB value stuff
 }
 
 or this:
 
 auto var = typeid(int);
 
 if(auto type = var.peek!TypeInfo) {
      // Do DB NULL stuff
 } else {
      // Do DB value stuff
 }
 
 ?
 
 I don't care about adding functionality X; you can already build a
 null-able DB type on top of Variant (see above, or use Nullable!Vairant,
 etc). I care about making variant (or Algebraic) _into_ a null-able DB
 type. So that it composes integrates well with the rest of our
 code-bases.
 
 It is not essential, but it would make a database interface using
 variants easier to code and to use. Probably we should just forget the
 idea.

 Steve

Databases and their ilk are a pretty big and important use case. So I think cleanly supporting them is necessary. That said, there are lots of alternatives available.

Robert, I guess I was reacting to your worry about the std.typecons Nullable!T, and Steve S's objection to 'muddying' Variant by including specifically database oriented stuff. A simple mark seemed more general purpose and possibly more acceptable. From your examples, I like Variant var = 1; var.nullify; if(var.isNull) { // Do DB NULL stuff } else { // Do DB value stuff } As long as when it is nullified I can still use var.type and get int. I take it that in the case of this example hasValue() would signify that the Variant was 'raw' - we don't really have uninitialized in D. Steve
Oct 29 2011
prev sibling next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 27-10-2011 15:12, Steve Teale wrote:
 How big a deal would it be to add a NULL indicator to the VariantN struct.

 I use the term NULL as opposed to null deliberately. Variant already
 provides the hasValue() method, which can serve as a null indicator. But
 in using it as a parameter in database modules, it would be useful to be
 able to give a Variant instance a type, as in v = "", but also to set it
 explicitly as NULL with setNull() or whatever.

 Could this fly without breaking existing code?

 Steve

I'm not sure having three possible states in Variant is a good idea, but maybe I'm not quite following. Doesn't it already carry type information when not set to a value? - Alex
Oct 27 2011
parent reply Steve Teale <steve.teale britseyeview.com> writes:
 
 I'm not sure having three possible states in Variant is a good idea, but
 maybe I'm not quite following.
 
 Doesn't it already carry type information when not set to a value?
 
 - Alex

Don't believe so. If you haven't set any value, hasValue() will return false, so it is kind of null, and it is not associated with a type - how would it know? Steve
Oct 27 2011
parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 27-10-2011 15:54, Steve Teale wrote:
 I'm not sure having three possible states in Variant is a good idea, but
 maybe I'm not quite following.

 Doesn't it already carry type information when not set to a value?

 - Alex

Don't believe so. If you haven't set any value, hasValue() will return false, so it is kind of null, and it is not associated with a type - how would it know? Steve

You're completely right; brain failed me for a moment there. OK, so I think introducing a constructor (or something like that) taking a TypeInfo object is a reasonable approach to setting it to no value, but still carrying a type. - Alex
Oct 27 2011
prev sibling next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 27 Oct 2011 09:12:26 -0400, Steve Teale <steve.teale britseyeview.com>
wrote:

 How big a deal would it be to add a NULL indicator to the VariantN struct.

 I use the term NULL as opposed to null deliberately. Variant already
 provides the hasValue() method, which can serve as a null indicator. But
 in using it as a parameter in database modules, it would be useful to be
 able to give a Variant instance a type, as in v = "", but also to set it
 explicitly as NULL with setNull() or whatever.

 Could this fly without breaking existing code?

 Steve

Any reason making a custom NULL type wouldn't work? i.e: struct NULL {} Variant var = NULL; assert(var.type == typeof(NULL));
Oct 27 2011
next sibling parent reply Steve Teale <steve.teale britseyeview.com> writes:
 Any reason making a custom NULL type wouldn't work? i.e:
 
 struct NULL {}
 
 Variant var = NULL;
 
 assert(var.type == typeof(NULL));

I don't think that is any improvement on hasValue(). It would tell you the particular value was null, but would not tell you what type it was. In a typical situation you need to tell the database server the type of the parameter, even if it is null. Steve
Oct 27 2011
parent Kagamin <spam here.lot> writes:
Steve Teale Wrote:

 Any reason making a custom NULL type wouldn't work? i.e:
 
 struct NULL {}
 
 Variant var = NULL;
 
 assert(var.type == typeof(NULL));

I don't think that is any improvement on hasValue(). It would tell you the particular value was null, but would not tell you what type it was. In a typical situation you need to tell the database server the type of the parameter, even if it is null.

SQL uses `NULL` for all types. Did you try Algebraic - type-restricted version of Variant?
Oct 27 2011
prev sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Fri, 28 Oct 2011 01:00:28 -0400, Kagamin wrote:
 SQL uses `NULL` for all types.

Yes, but if you set a particular column value to NULL, it does not wipe away the column's meta-data.
 Did you try Algebraic - type-restricted version of Variant?

SQL implementations tend to use structure types for time and date and such. Steve
Oct 28 2011
prev sibling next sibling parent kennytm <kennytm gmail.com> writes:
Steve Teale <steve.teale britseyeview.com> wrote:
 How big a deal would it be to add a NULL indicator to the VariantN struct.
 
 I use the term NULL as opposed to null deliberately. Variant already 
 provides the hasValue() method, which can serve as a null indicator. But 
 in using it as a parameter in database modules, it would be useful to be 
 able to give a Variant instance a type, as in v = "", but also to set it 
 explicitly as NULL with setNull() or whatever.
 
 Could this fly without breaking existing code?
 
 Steve

Just store a std.typecons.Nullable!T in the Variant.
Oct 27 2011
prev sibling parent Steve Teale <steve.teale britseyeview.com> writes:
On Thu, 27 Oct 2011 18:35:19 +0000, kennytm wrote:

 Just store a std.typecons.Nullable!T in the Variant.

Mmm - works to some extent, but by the time you'd wrapped it to make the semantics half comprehensible I think it would have been better to simply wrap VariantN to add an extra bool. Steve
Oct 27 2011