Need help with implementation of variant-array

General FreeBASIC programming questions.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

fxm wrote:About that, I am waiting the dkl's response but I think that none object (static, dynamic and temporary) should be authorized to be created from a Type that does not implement all abstract methods.
Maybe. If I do that adding all abstract stuff everywhere, it's true that the compiler now is ok, but now it's a little uggly. Objects not concerned by some features have to integrate them, making all the child potentially very big due to stuff that are not of their concern.
For instance MinValue is a property for the integercap type, why should it be introduced in singlecap, zstringcap, and everything you can imagine if I extend the things more. If it's really necessary, there should be a keyword to mean fake implementation to avoid the real fake implementation effort and make the compiler understand why (maybe VIRTUAL FAKE or anything, I don't know how this issue is handled in other languages).

Code: Select all

'*root*         -> TYPECAP                                         
'integer        -> INTEGERCAP                                     
'single         -> SINGLECAP                                       
'zstring_ptr    -> ZSTRINGPTRCAP                                   


type TYPECAP extends OBJECT
    declare abstract operator cast() as integer
    declare abstract operator cast() as single
    declare abstract operator cast() as string
    declare abstract property MinValue() as integer
    declare abstract property MaxValue() as integer
    declare abstract property ClosestToZeroValue() as single
    declare abstract property ClosestToInfValue() as single
    declare abstract function GetType() as string
    declare abstract function ToString() as string
end type
type VARIANT as TYPECAP ptr


type INTEGERCAP extends TYPECAP
    declare constructor()
    declare constructor(byval I as integer)
    declare virtual property MinValue() as integer override
    declare virtual property MaxValue() as integer override
    declare virtual property ClosestToZeroValue() as single override
    declare virtual property ClosestToInfValue() as single override
    declare operator let(byref as integer)
    declare virtual operator cast() as integer override
    declare virtual operator cast() as single override
    declare virtual operator cast() as string override
    declare virtual function GetType() as string override
    declare virtual function ToString() as string override
        as integer  _value
end type
constructor INTEGERCAP()
    BASE()
end constructor
constructor INTEGERCAP(byval I as integer)
	BASE()
	THIS._value => I
end constructor
property INTEGERCAP.MinValue() as integer
	#if __FB_64BIT__
	    dim as integer min => &H8000000000000000
	#else
	    dim as integer min => &H80000000
	#endif
	'---->
	return min
end property
property INTEGERCAP.MaxValue() as integer
	#if __FB_64BIT__
	    dim as integer max => &H7FFFFFFFFFFFFFFF
	#else
	    dim as integer max => &H7FFFFFFF
	#endif
	'---->
	return max
end property
property INTEGERCAP.ClosestToZeroValue() as single

end property
property INTEGERCAP.ClosestToInfValue() as single

end property
operator INTEGERCAP.let(byref LetValue as integer)
    THIS._value = LetValue
end operator
operator INTEGERCAP.cast() as integer
    '---->
    return THIS._value
end operator
operator INTEGERCAP.cast() as single
    '---->
    return THIS._value
end operator
operator INTEGERCAP.cast() as string
    '---->
    return Str(THIS._value)
end operator
function INTEGERCAP.GetType() as string
    '---->
    return "integercap"
end function
function INTEGERCAP.ToString() as string
	'---->
	return str(THIS._value)
end function

type SINGLECAP extends TYPECAP
    declare constructor()
    declare constructor(byval S as single)
    declare virtual property MinValue() as integer override
    declare virtual property MaxValue() as integer override
    declare virtual property ClosestToZeroValue() as single override
    declare virtual property ClosestToInfValue() as single override
    declare operator let(byref as single)
    declare virtual operator cast() as integer override
    declare virtual operator cast() as single override
    declare virtual operator cast() as string override
    declare virtual function GetType() as string override
    declare virtual function ToString() as string override
        as single  _value
end type
constructor SINGLECAP()
    BASE()
end constructor
constructor SINGLECAP(byval S as single)
	BASE()
	THIS._value => S
end constructor
property SINGLECAP.MinValue() as integer

end property
property SINGLECAP.MaxValue() as integer

end property
property SINGLECAP.ClosestToZeroValue() as single
	'---->
	return 1.401298e-45 
end property
property SINGLECAP.ClosestToInfValue() as single
	'---->
	return 3.402823e+38
end property
operator SINGLECAP.let(byref LetValue as single)
    THIS._value = LetValue
end operator
operator SINGLECAP.cast() as integer
    '---->
    return THIS._value
end operator
operator SINGLECAP.cast() as single
    '---->
    return THIS._value
end operator
operator SINGLECAP.cast() as string
    '---->
    return Str(THIS._value)
end operator
function SINGLECAP.GetType() as string
    '---->
    return "singlecap"
end function
function SINGLECAP.ToString() as string
	'---->
	return str(THIS._value)
end function

type ZSTRINGPTRCAP extends TYPECAP
    declare constructor()
    declare constructor(byval Z as zstring ptr)
    declare operator let(byref as zstring ptr)
    declare virtual property MinValue() as integer override
    declare virtual property MaxValue() as integer override
    declare virtual property ClosestToZeroValue() as single override
    declare virtual property ClosestToInfValue() as single override
    declare virtual operator cast() as integer override
    declare virtual operator cast() as single override
    declare virtual operator cast() as string override
    declare virtual function GetType() as string override
    declare virtual function ToString() as string override
        as zstring ptr  _value
end type
constructor ZSTRINGPTRCAP()
    BASE()
end constructor
constructor ZSTRINGPTRCAP(byval Z as zstring ptr)
    BASE()
    THIS._value => Z
end constructor
property ZSTRINGPTRCAP.MinValue() as integer

end property
property ZSTRINGPTRCAP.MaxValue() as integer

end property
property ZSTRINGPTRCAP.ClosestToZeroValue() as single

end property
property ZSTRINGPTRCAP.ClosestToInfValue() as single

end property
operator ZSTRINGPTRCAP.let(byref LetValue as zstring ptr)
    THIS._value = LetValue
end operator
operator ZSTRINGPTRCAP.cast() as integer
    '---->
    return Val(*THIS._value)
end operator
operator ZSTRINGPTRCAP.cast() as single
    '---->
    return Val(*THIS._value)
end operator
operator ZSTRINGPTRCAP.cast() as string
    '---->
    return *THIS._value
end operator
function ZSTRINGPTRCAP.GetType() as string
    '---->
    return "zstringptrcap"
end function
function ZSTRINGPTRCAP.ToString() as string
	'---->
	return *THIS._value
end function

'````````````````````````````````````````````````````````````````````
'define an array of variant
dim as VARIANT   arrayOfVariant(any)

'fill the array
redim arrayOfVariant(1 to 3)
arrayOfVariant(1) = new INTEGERCAP(99)
arrayOfVariant(2) = new SINGLECAP(3.1415)
arrayOfVariant(3) = new ZSTRINGPTRCAP("hello_variant")

'now you can get back the type of each variable stored as well as its value
? 1, arrayOfVariant(1)->GetType(), *arrayOfVariant(1)
? 2, arrayOfVariant(2)->GetType(), *arrayOfVariant(2)
? 3, arrayOfVariant(3)->GetType(), *arrayOfVariant(3)
?

'some operations
? "? 1+2+3", *arrayOfVariant(1) + *arrayOfVariant(2) + *arrayOfVariant(3)
? "? 1&2&3", *arrayOfVariant(1) & *arrayOfVariant(2) & *arrayOfVariant(3)
?

'other operations
? *arrayOfVariant(1) + *arrayOfVariant(2)
? *arrayOfVariant(1) & *arrayOfVariant(2)
? *arrayOfVariant(3)
?


'ToString method
? (type<SINGLECAP>(*arrayOfVariant(2) + *arrayOfVariant(1))).ToString()
? (SINGLECAP(*arrayOfVariant(2) + *arrayOfVariant(1))).ToString()


? arrayOfVariant(2)->ToString()
? arrayOfVariant(3)->ToString()

? arrayOfVariant(2)->ClosestToZeroValue

'````````````````````````````````````````````````````````````````````
getKey()

'(eof)
So I wonder now, we had to introduce ABSTRACT/VIRTUAL to access the _value field of child objects. But the value field is really common to every child. Now we have methods that are not common to everyone, Is there an other way that handles this case and would allow the child procedure access from the base?
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Need help with implementation of variant-array

Post by fxm »

The methods that are not common to all derived Types may be declared as virtual in the base Type with an implementation by default only once in the base Type:

Code: Select all

'*root*         -> TYPECAP                                         
'integer        -> INTEGERCAP                                     
'single         -> SINGLECAP                                       
'zstring_ptr    -> ZSTRINGPTRCAP                                   


type TYPECAP extends OBJECT
    declare abstract operator cast() as integer
    declare abstract operator cast() as single
    declare abstract operator cast() as string
    declare virtual property MinValue() as integer
    declare virtual property MaxValue() as integer
    declare virtual property ClosestToZeroValue() as single
    declare virtual property ClosestToInfValue() as single
    declare abstract function GetType() as string
    declare abstract function ToString() as string
end type
property TYPECAP.MinValue() as integer
end property
property TYPECAP.MaxValue() as integer
end property
property TYPECAP.ClosestToZeroValue() as single
end property
property TYPECAP.ClosestToInfValue() as single
end property
Type VARIANT as TYPECAP ptr


type INTEGERCAP extends TYPECAP
    declare constructor()
    declare constructor(byval I as integer)
    declare virtual property MinValue() as integer override
    declare virtual property MaxValue() as integer override
    declare operator let(byref as integer)
    declare virtual operator cast() as integer override
    declare virtual operator cast() as single override
    declare virtual operator cast() as string override
    declare virtual function GetType() as string override
    declare virtual function ToString() as string override
        as integer  _value
end type
constructor INTEGERCAP()
    BASE()
end constructor
constructor INTEGERCAP(byval I as integer)
   BASE()
   THIS._value => I
end constructor
property INTEGERCAP.MinValue() as integer
   #if __FB_64BIT__
       dim as integer min => &H8000000000000000
   #else
       dim as integer min => &H80000000
   #endif
   '---->
   return min
end property
property INTEGERCAP.MaxValue() as integer
   #if __FB_64BIT__
       dim as integer max => &H7FFFFFFFFFFFFFFF
   #else
       dim as integer max => &H7FFFFFFF
   #endif
   '---->
   return max
end property
operator INTEGERCAP.let(byref LetValue as integer)
    THIS._value = LetValue
end operator
operator INTEGERCAP.cast() as integer
    '---->
    return THIS._value
end operator
operator INTEGERCAP.cast() as single
    '---->
    return THIS._value
end operator
operator INTEGERCAP.cast() as string
    '---->
    return Str(THIS._value)
end operator
function INTEGERCAP.GetType() as string
    '---->
    return "integercap"
end function
function INTEGERCAP.ToString() as string
   '---->
   return str(THIS._value)
end function

type SINGLECAP extends TYPECAP
    declare constructor()
    declare constructor(byval S as single)
    declare virtual property ClosestToZeroValue() as single override
    declare virtual property ClosestToInfValue() as single override
    declare operator let(byref as single)
    declare virtual operator cast() as integer override
    declare virtual operator cast() as single override
    declare virtual operator cast() as string override
    declare virtual function GetType() as string override
    declare virtual function ToString() as string override
        as single  _value
end type
constructor SINGLECAP()
    BASE()
end constructor
constructor SINGLECAP(byval S as single)
   BASE()
   THIS._value => S
end constructor
property SINGLECAP.ClosestToZeroValue() as single
   '---->
   return 1.401298e-45
end property
property SINGLECAP.ClosestToInfValue() as single
   '---->
   return 3.402823e+38
end property
operator SINGLECAP.let(byref LetValue as single)
    THIS._value = LetValue
end operator
operator SINGLECAP.cast() as integer
    '---->
    return THIS._value
end operator
operator SINGLECAP.cast() as single
    '---->
    return THIS._value
end operator
operator SINGLECAP.cast() as string
    '---->
    return Str(THIS._value)
end operator
function SINGLECAP.GetType() as string
    '---->
    return "singlecap"
end function
function SINGLECAP.ToString() as string
   '---->
   return str(THIS._value)
end function

type ZSTRINGPTRCAP extends TYPECAP
    declare constructor()
    declare constructor(byval Z as zstring ptr)
    declare operator let(byref as zstring ptr)
    declare virtual operator cast() as integer override
    declare virtual operator cast() as single override
    declare virtual operator cast() as string override
    declare virtual function GetType() as string override
    declare virtual function ToString() as string override
        as zstring ptr  _value
end type
constructor ZSTRINGPTRCAP()
    BASE()
end constructor
constructor ZSTRINGPTRCAP(byval Z as zstring ptr)
    BASE()
    THIS._value => Z
end constructor
operator ZSTRINGPTRCAP.let(byref LetValue as zstring ptr)
    THIS._value = LetValue
end operator
operator ZSTRINGPTRCAP.cast() as integer
    '---->
    return Val(*THIS._value)
end operator
operator ZSTRINGPTRCAP.cast() as single
    '---->
    return Val(*THIS._value)
end operator
operator ZSTRINGPTRCAP.cast() as string
    '---->
    return *THIS._value
end operator
function ZSTRINGPTRCAP.GetType() as string
    '---->
    return "zstringptrcap"
end function
function ZSTRINGPTRCAP.ToString() as string
   '---->
   return *THIS._value
end function

'````````````````````````````````````````````````````````````````````
'define an array of variant
dim as VARIANT   arrayOfVariant(any)

'fill the array
redim arrayOfVariant(1 to 3)
arrayOfVariant(1) = new INTEGERCAP(99)
arrayOfVariant(2) = new SINGLECAP(3.1415)
arrayOfVariant(3) = new ZSTRINGPTRCAP("hello_variant")

'now you can get back the type of each variable stored as well as its value
? 1, arrayOfVariant(1)->GetType(), *arrayOfVariant(1)
? 2, arrayOfVariant(2)->GetType(), *arrayOfVariant(2)
? 3, arrayOfVariant(3)->GetType(), *arrayOfVariant(3)
?

'some operations
? "? 1+2+3", *arrayOfVariant(1) + *arrayOfVariant(2) + *arrayOfVariant(3)
? "? 1&2&3", *arrayOfVariant(1) & *arrayOfVariant(2) & *arrayOfVariant(3)
?

'other operations
? *arrayOfVariant(1) + *arrayOfVariant(2)
? *arrayOfVariant(1) & *arrayOfVariant(2)
? *arrayOfVariant(3)
?


'ToString method
? (type<SINGLECAP>(*arrayOfVariant(2) + *arrayOfVariant(1))).ToString()
? (SINGLECAP(*arrayOfVariant(2) + *arrayOfVariant(1))).ToString()


? arrayOfVariant(2)->ToString()
? arrayOfVariant(3)->ToString()

? arrayOfVariant(2)->ClosestToZeroValue

'````````````````````````````````````````````````````````````````````
getKey()

'(eof)
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

fxm wrote:The methods that are not common to all derived Types may be declared as virtual in the base Type with an implementation by default only once in the base Type
Thanks very much for those corrections about ABSTRACT/VIRTUAL. Now I've another question however because I can do:

Code: Select all

print arrayOfVariant(3)->ClosestToZeroValue
Here arrayOfVariant(3) is a ZSTRINGPTRCAP, it has no ClosestToZeroValue property, but it returns 0. I can not make them private at the BASE level, and then change the access at the child levels, this doesn't work.
Of course it's not a big error, but it's introducing some nonsense. Not every child has to call any property but how would it be possible to forbid the access, it seems impossible.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Need help with implementation of variant-array

Post by fxm »

I do not see how to cause a compilation error but only a runtime error:

Code: Select all

property TYPECAP.ClosestToZeroValue() as single
    print
    print "*** property 'ClosestToZeroValue() as single' not implemented for this object";
    error 1
end property
or only a program termination,
or simply a runtime comment.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

fxm wrote:I do not see how to cause a compilation error but only a runtime error:

Code: Select all

property TYPECAP.ClosestToZeroValue() as single
    print
    print "*** property 'ClosestToZeroValue() as single' not implemented for this object";
    error 1
end property
or only a program termination,
or simply a runtime comment.
Yes, thanks. I think here this is something that can only be handled by a compiler marker. Anyway that's a nice illustration of the usage of ABSTRACT and VIRTUAL. At least this answers a simple and concrete everyday possible need. Nice.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Need help with implementation of variant-array

Post by fxm »

fxm wrote:@dkl,

The syntax "UDT()" accepts to create a temporary object of a Type that does not implement an abstract method!

(The syntax "Type<UDT>()" refuses this as normally expected)
Bug report filled:
#836 "UDT()" agrees to create temporary object of type "UDT" that does not implement abstract method
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Need help with implementation of variant-array

Post by fxm »

Now bug fixed.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

After the challenge topic with explanations of run-time type that knows how to reach virtual stuff of a udt inheritance lineage, I tried to simplify the previous implementation.

In the code below, I've many difficulties with Cast/Let. The base cast and let tends to be called while they are useless.
First question is why I cant make them abstract in the code?

Then I've some other unwished behaviours with converting but maybe the problem is the same as the fact that abstract doesn't work.

Thanks if anyone knows something about this.

Code: Select all

 'About VARIANT, new version


'--------------------------------------VARIANT BASE TYPE
type VARIANT extends OBJECT
    declare constructor()
    declare constructor(byref TypeId as const string, _ 
                        ValuePtr as any ptr=0)
    '
    'QUESTION: WHY CAN NOT BE ABSTRACT BELOW (CAST AND LET)
    declare virtual operator cast() as integer      
    declare virtual operator let(as integer)
    declare virtual operator cast() as double      
    declare virtual operator let(as double)        
    '
    declare virtual property ToString() as string
    declare virtual property GetType() as string
end type
constructor VARIANT()
    'the type dependent constructor
    'is implemented after all variant derived types are declared
end constructor
'''
'USELESS, BUT CANT ABSTRACT (CAST, LET):
virtual operator VARIANT.cast() as integer
    return -1
end operator
virtual operator VARIANT.let(LetValue as integer)
    '
end operator
virtual operator VARIANT.cast() as double
    return -.9
end operator
virtual operator VARIANT.let(LetValue as double)
    '
end operator
''''
virtual property VARIANT.ToString() as string
    return "NO_VALUE"
end property
virtual property VARIANT.GetType() as string
    return "VARIANT:BASE"
end property


'--------------------------------------VARIANT INTEGER TYPE
type VARINTEGER extends VARIANT
    declare constructor()
    declare operator cast() as integer      override 
    declare operator let(as integer)        override
    declare property Value(as integer)
    declare property ToString() as string   override
    declare property GetType() as string    override
        as integer  _value
end type
constructor VARINTEGER()
    BASE()
end constructor
operator VARINTEGER.cast() as integer
    return THIS._value
end operator
operator VARINTEGER.let(LetValue as integer)
    THIS._value = LetValue
end operator
property VARINTEGER.Value(SetValue as integer)
    THIS._value = SetValue
end property
property VARINTEGER.ToString() as string
    return str(THIS._value)
end property
property VARINTEGER.GetType() as string
    return "VARIANT:"& uCase("integer")
end property


'--------------------------------------VARIANT DOUBLE TYPE
type VARDOUBLE extends VARIANT
    declare constructor()
    declare operator cast() as double      override 
    declare operator let(as double)        override
    declare property Value(as double)
    declare property ToString() as string   override
    declare property GetType() as string    override
        as double  _value
end type
constructor VARDOUBLE()
    BASE()
end constructor
operator VARDOUBLE.cast() as double
    return THIS._value
end operator
operator VARDOUBLE.let(LetValue as double)
    THIS._value = LetValue
end operator
property VARDOUBLE.Value(SetValue as double)
    THIS._value = SetValue
end property
property VARDOUBLE.ToString() as string
    return str(THIS._value)
end property
property VARDOUBLE.GetType() as string
    return "VARIANT:"& uCase("double")
end property


'--------------------------------------VARIANT BASE TYPE FINAL CONSTRUCTOR
constructor VARIANT(byref TypeId as const string, ValuePtr as any ptr=0)
    select case trim(lCase(TypeId))
    case "integer", "varinteger"
        poke any ptr, @THIS, peek(any ptr, @type<VARINTEGER>())
        *cPtr( _ 
                integer ptr, cInt(@THIS) + _ 
                offsetOf(VARINTEGER, _value) _ 
              ) => *cast(integer ptr, ValuePtr)
    case "double", "vardouble"
        poke any ptr, @THIS, peek(any ptr, @type<VARDOUBLE>())
        *cPtr( _ 
                double ptr, cInt(@THIS) + _ 
                offsetOf(VARDOUBLE, _value) _ 
              ) => *cast(double ptr, ValuePtr)
    case else
        '
    end select
end constructor


'-----------------------------------------
'----------------------------------TEST---

dim as integer i = 111
dim as VARIANT  x => VARIANT("integer", @i)
#print typeOf(x)
? cInt(x), """"& x.ToString &"""", x.GetType
x = 9
? cInt(x) , """"& x.ToString &"""", x.GetType
''problem, no conversion done:
x = 67.89
? cInt(x) , """"& x.ToString &"""", x.GetType


dim as double d = 9.13402
dim as VARIANT y => VARIANT("double", @d)
#print typeOf(y)
? cDbl(y), """"& y.ToString &"""", y.GetType
y = 2.
? cDbl(y) , """"& y.ToString &"""", y.GetType
''problem, no conversion done:
y = 1
? cDbl(y) , """"& y.ToString &"""", y.GetType   


''to be fixed also:
? : ? cInt(x) + cDbl(y)
? x + y

'-----------------------------------------
getKey()
'(eof)
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Need help with implementation of variant-array

Post by fxm »

To be able to implement a type, all procedures declared at its level or above in the inheritance hierarchy must be implemented, seen from its level.
In particular, a type containing at least one abstract declaration cannot be implemented.

Warning:
When you construct an instance of VARIANT, the _value field (integer or double) is not allocated in memory, even if you modify after its run-time type to VARINTEGER or VARDOUBLE (by overwritting its vptr).
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

fxm wrote:To be able to implement a type, all procedures declared at its level or above in the inheritance hierarchy must be implemented, seen from its level.
In particular, a type containing at least one abstract declaration cannot be implemented.
Hi fxm,
you mean that ABSTRACT is blocking the instanciation?
I think it's something desserving maybe a reformulation in the doc. Simpler approach is to start by notifying that by no means a udt containing abstract content can be instancied (dimmed is possibly even clearer). But it can be used as an effective static members/procedures container.
After all, sometimes we need only a static container, and sometimes we want instanciations.
Talking about objects creations and implementing abstract has, at least for me, been confusing.
Thanks anyway.
fxm wrote: Warning:
When you construct an instance of VARIANT, the _value field (integer or double) is not allocated in memory, even if you modify after its run-time type to VARINTEGER or VARDOUBLE (by overwritting its vptr).
I failed to use a forward type. But maybe I've missed something. So I dont see for the moment when and how allocating the memory for the future child. Maybe I need a forward pointer member.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Need help with implementation of variant-array

Post by fxm »

ABSTRACT:
.....
Description:
Abstract is a special form of Virtual. The difference is that abstract methods do not have a body, but just the declaration. Essentially this allows the declaration of an interface which can be implemented by various derived types.

In order to call an abstract method, it must have been overridden and implemented by a derived data type, or else the program will abort.
As a result, only types that implement all the abstract methods are allowed to create objects. For the same reason, a constructor should not call an unimplemented method.

Constructors cannot be abstract, since they cannot be virtual. In addition, abstract destructors are not supported either, because a destructor body (no matter whether implicit or explicit) is needed in order to call base and field destructors.

Abstracts are called "pure virtual" in C++ (unlike FreeBASIC, C++ allows pure virtuals to have a body, but accessible only statically).
.....
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

fxm wrote: In order to call an abstract method, it must have been overridden and implemented by a derived data type, or else the program will abort.
As a result, only types that implement all the abstract methods are allowed to create objects.
I've already started by reading the doc before using abstract. I also didn't understand your previous remark here but decided to make many tests guided by the fact this shouldn't work finally. That's only when I added a dim statement that I've understood. That's why for me this is the key point. In short, no dimming if the udt contains abstract.
I know that create object may look synonymous to dim an object, but it didn't for me. For me you create an object when you design it , not only at instancing (and for a static container object abstract is not blocking). Just vocabulary any way. Hopefully, it will be clear enough in general.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Need help with implementation of variant-array

Post by fxm »

Not DIMming is not the better rule because one can do that:

Code: Select all

Type Parent Extends Object
  Declare Abstract Sub s ()
  Declare Virtual Destructor ()
End Type
Virtual Destructor Parent ()
End Destructor

Type Child Extends Parent
  Declare Virtual Sub s () Override
  Declare Virtual Destructor () Override
End Type
Virtual Sub Child.s ()
  Print "Child.s()"
End Sub
Virtual Destructor Child ()
  Print "Destructor Child()"
End Destructor

Dim As Parent Ptr pc = New Child()
pc->s()
Delete pc
Print

'or

Dim Byref As Parent rc = *New Child()
rc.s()
Delete @rc
Print

Sleep
Last edited by fxm on Dec 26, 2016 6:14, edited 2 times in total.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

In the case here, I'm using virtuality in fact. And because I consider that I've nothing to implement in VARIANT , I want to make things abstract. That's where I get stuck between the necessity to remove implementation, and in the other hand the compiler complaining about no implementation. The problem is to be taken in this way to be precise. So maybe the true affirmation is that one can not exchange virtual for abstract on the reason of an undefined (or empty) implementation, if there is a at any level an instanciation of the class (and it can be well hidden as your code shows).
Of course it's not the most general case but I've felt into it :)
Anyway, this seems to underline that abstract is for pure interfaces not for a light version of virtual? ( so it makes abstract not backward related to virtual , it's more virtual that is a special case of abstract in this case at least , I mean if abstract works virtual will, but not the contrary)
Description:
Abstract is a special form of Virtual. The difference is that abstract methods do not have a body, but just the declaration.Essentially this allows the declaration of an interface which can be implemented by various derived types.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Need help with implementation of variant-array

Post by Tourist Trap »

RTT would require some helper in FB to be more manageable.
I've fixed many things now, but the simple fact that cast and let needs to be declared before they really are made actual is not leading to lightweighted polymorphism.

Anyway, I've only one question here. Why the value is broken when an array is used?
Things are doing their job in case of simple variables, at least in the example. I don't get the trick occuring here with the array.

Code: Select all

 'About VARIANT with RTT

'--------------------------------------VARIANT BASE TYPE
type VARINTEGER_FWD     as VARINTEGER ptr
type VARDOUBLE_FWD      as VARDOUBLE ptr
type VARIANT extends OBJECT
    declare constructor()
    declare constructor(CallerPtr as VARIANT ptr, _
                        byref TypeId as const string, _ 
                        ValuePtr as any ptr, _ 
                        DerivedTypePtr as any ptr)
    '
    declare virtual operator cast() as integer      
    declare virtual operator let(as integer)
    declare virtual property Value(as integer)
        as VARINTEGER_FWD   _viPtr
    declare virtual operator cast() as double      
    declare virtual operator let(as double)
    declare virtual property Value(as double)
        as VARDOUBLE_FWD    _vdPtr
    '
    declare virtual property ToString() as string
    declare virtual property GetType() as string
end type
constructor VARIANT()
    '* the type dependent constructor  
    '* is implemented after all variant
    '* derived types have been declared
end constructor
virtual operator VARIANT.cast() as integer
    '- - - - -
end operator
virtual operator VARIANT.let(LetValue as integer)
    '- - - - -
end operator
property VARIANT.Value(SetValue as integer)
    '- - - - -
end property
virtual operator VARIANT.cast() as double
    '- - - - -
end operator
virtual operator VARIANT.let(LetValue as double)
    '- - - - -
end operator
property VARIANT.Value(SetValue as double)
    '- - - - -
end property
virtual property VARIANT.ToString() as string
    return "NO_VALUE"
end property
virtual property VARIANT.GetType() as string
    return "VARIANT:BASE"
end property

'--------------------------------------VARIANT INTEGER TYPE
type VARINTEGER extends VARIANT
    declare constructor()
    declare operator cast() as integer      override 
    declare operator let(as integer)        override
    declare property Value(as integer)      override
    declare property ToString() as string   override
    declare property GetType() as string    override
        as integer  _value
end type
constructor VARINTEGER()
    BASE()
end constructor
operator VARINTEGER.cast() as integer
    THIS._value = THIS._viPtr->_value
    return THIS._viPtr->_value
end operator
operator VARINTEGER.let(LetValue as integer)
    delete ( THIS._viPtr)
    THIS._viPtr => new VARINTEGER()
    THIS._viPtr->_value = LetValue
    THIS._value = LetValue
end operator
property VARINTEGER.Value(SetValue as integer)
    delete ( THIS._viPtr)
    THIS._viPtr => new VARINTEGER()
    THIS._viPtr->_value = SetValue
    THIS._value = SetValue
end property
property VARINTEGER.ToString() as string
    return str(THIS._value)
end property
property VARINTEGER.GetType() as string
    return "VARIANT:"& uCase("integer")
end property

'--------------------------------------VARIANT DOUBLE TYPE
type VARDOUBLE extends VARIANT
    declare constructor()
    declare operator cast() as double      override 
    declare operator let(as double)        override
    declare property Value(as double)       override
    declare property ToString() as string   override
    declare property GetType() as string    override
        as double  _value
end type
constructor VARDOUBLE()
    BASE()
end constructor
operator VARDOUBLE.cast() as double
    THIS._value = THIS._vdPtr->_value
    return THIS._vdPtr->_value
end operator
operator VARDOUBLE.let(LetValue as double)
    delete ( THIS._vdPtr)
    THIS._vdPtr => new VARDOUBLE()
    THIS._vdPtr->_value = LetValue
    THIS._value = LetValue
end operator
property VARDOUBLE.Value(SetValue as double)
    delete ( THIS._vdPtr)
    THIS._vdPtr => new VARDOUBLE()
    THIS._vdPtr->_value = SetValue
    THIS._value = SetValue
end property
property VARDOUBLE.ToString() as string
    return str(THIS._value)
end property
property VARDOUBLE.GetType() as string
    return "VARIANT:"& uCase("double")
end property

'--------------------------------------VARIANT BASE TYPE FINAL CONSTRUCTOR
constructor VARIANT(CallerPtr as VARIANT ptr, _
                    byref TypeId as const string, _ 
                    ValuePtr as any ptr, _ 
                    DerivedTypePtr as any ptr)
    select case trim(lCase(TypeId))
    case "integer", "varinteger"
        'set the RTT(THIS) = VtablePtr(DERIVED)
            poke any ptr, iif(CallerPtr=0,@THIS,CallerPtr), peek(any ptr, @type<VARINTEGER>())
        'get some instancied pointer on the derived type
            delete (THIS._viPtr)
            THIS._viPtr = DerivedTypePtr
        'put an initial value in the persistent member field
            *cast(VARINTEGER ptr, THIS._viPtr) = *cast(integer ptr, ValuePtr)
    case "double", "vardouble"
        'set the RTT(THIS) = VtablePtr(DERIVED)
            poke any ptr, iif(CallerPtr=0,@THIS,CallerPtr), peek(any ptr, @type<VARDOUBLE>())
        'get some instancied pointer on the derived type
            delete (THIS._vdPtr)
            THIS._vdPtr = DerivedTypePtr
        'put an initial value in the persistent member field
            *cast(VARDOUBLE ptr, THIS._vdPtr) = *cast(double ptr, ValuePtr)
    case else
        '
    end select
end constructor





'-----------------------------------------
'----------------------------------TEST---

dim as VARIANT  x => VARIANT(@x, "varinteger", new integer(741), new VARINTEGER())
#print typeOf(x)
? cInt(x), """"& x.ToString &"""", x.GetType
x = 9
? cInt(x) , """"& x.ToString &"""", x.GetType
x = 67.8998     ''conversion is failing
? cInt(x) , """"& x.ToString &"""", x.GetType

?

x => VARIANT(@x, "vardouble", new double(1.41), new VARDOUBLE())
poke any ptr, @x, peek(any ptr, @type<VARDOUBLE>())
#print typeOf(x)
? cDbl(x), """"& x.ToString &"""", x.GetType
x = 4.5
? cDbl(x) , """"& x.ToString &"""", x.GetType
x = 111#
? cDbl(x) , """"& x.ToString &"""", x.GetType   

?

dim as VARIANT t(0 to 1)
t(0) = VARIANT(@t(0), "integer", new integer(999), new VARINTEGER())
t(1) = VARIANT(@t(1), "double", new double(0.111), new VARDOUBLE())

? t(0).GetType, t(0).ToString
? t(1).GetType, t(1).ToString

'-----------------------------------------
getKey()
'(eof)
/'
dim as VARIANT y => VARIANT("double", new double(1.41), new VARDOUBLE())
#print typeOf(y)
? cDbl(y), """"& y.ToString &"""", y.GetType
y = 4.5
? cDbl(y) , """"& y.ToString &"""", y.GetType
y = 111#
? cDbl(y) , """"& y.ToString &"""", y.GetType   

? : ? "cInt(x) + cDbl(y)", cInt(x) + cDbl(y)
? "x.ToString", x.ToString
? "x + 0%", x + 0%
? "y + 0#", y + 0#
? "x + y", x + y
'/
Post Reply