polymorphism revisit - 2023

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: polymorphism revisit - 2023

Post by fxm »

dodicat wrote: Apr 11, 2023 9:48 I have seen similar before coder jeff + fxm I think
Was it threading perhaps?

In general, I always try to give an accurate answer to the question posed by the author.

In the above case, as long as the author wanted to be able to deal with different (non-static) member functions, I answered him with polymorphism.
When the author now talks about being able to handle static (non-member) functions, I answer him with a simple callback structure.
But as the first post was finally modified by the author, we no longer see this conductive path.
dafhi
Posts: 1640
Joined: Jun 04, 2005 9:51

Re: polymorphism revisit - 2023

Post by dafhi »

first post was to provide useful tool. i'd forgotten key features however, so this ended up being a "help pls"

final 2 examples i think are ridiculously useful
my long-ago idea was to procedurally generate a function path. it was for a palette generator. re-building
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: polymorphism revisit - 2023

Post by fxm »

When editing a post later (significantly, except for typos), it is best only to add an "edit" paragraph after the former post text to keep the discussion thread intact and therefore still understandable (one should not have ashamed of what we wrote first).
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: polymorphism revisit - 2023

Post by fxm »

Runtime Polymorphism versus Data Members

Runtime polymorphism cannot be applied directly to data members with FreeBASIC.
Example with static data members to better highlight this behavior:

Code: Select all

Type Animal Extends Object
    Static As String S
End Type
Dim As String Animal.S

Type Cat Extends Animal
    Static As String S
End Type
Dim As String Cat.S

Type Dog Extends Animal
    Static As String S
End Type
Dim As String Dog.S

Dim As String S0(...) = {"Animal", "Cat", "Dog"}


Dim As Animal Ptr p(...) = {New Animal, New Cat, New Dog}

For I As Integer = Lbound(p) To Ubound(p)
    p(I)->S = S0(I)
Next I

For I As Integer = Lbound(p) To Ubound(p)
    Print p(I)->S
Next I

For I As Integer = Lbound(p) To Ubound(p)
    Delete p(I)
Next I

Sleep
  • Code: Select all

    Dog
    Dog
    Dog
    
    (only 'Animal.S' is accessed)

A workaround can be to use virtual properties to access these data members.
Example with private static data members interfaced by public virtual properties:

Code: Select all

Type Animal Extends Object
    Public:
        Declare Virtual Property S(Byref sa As String)
        Declare Virtual Property S() As String
    Private:
        Static As String _S
End Type
Dim As String Animal._S

Property Animal.S() As String
    Return This._S
End Property

Property Animal.S(Byref sa As String)
    This._S = sa
End Property

Type Cat Extends Animal
    Public:
        Declare Virtual Property S(Byref sa As String)
        Declare Virtual Property S() As String
    Private:
        Static As String _S
End Type
Dim As String Cat._S

Property Cat.S() As String
    Return This._S
End Property

Property Cat.S(Byref sc As String)
    This._S = sc
End Property

Type Dog Extends Animal
    Public:
        Declare Virtual Property S(Byref sa As String)
        Declare Virtual Property S() As String
    Private:
        Static As String _S
End Type
Dim As String Dog._S

Property Dog.S() As String
    Return This._S
End Property

Property Dog.S(Byref sd As String)
    This._S = sd
End Property

Dim As String S0(...) = {"Animal", "Cat", "Dog"}


Dim As Animal Ptr p(...) = {New Animal, New Cat, New Dog}

For I As Integer = Lbound(p) To Ubound(p)
    p(I)->S = S0(I)
Next I

For I As Integer = Lbound(p) To Ubound(p)
    Print p(I)->S
Next I

For I As Integer = Lbound(p) To Ubound(p)
    Delete p(I)
Next I

Sleep
  • Code: Select all

    Animal
    Cat
    Dog
    
    ('Animal.S', 'Cat.S', and 'Dog.S' are well accessed sequentially)

Simpler code using a virtual function returning by reference a local static data, instead of 2 virtual properties ('get' and 'set') and a static data member:

Code: Select all

Type Animal Extends Object
    Declare Virtual Function S() Byref As String
End Type

Function Animal.S() Byref As String
    Static As String _S
    Return _S
End Function

Type Cat Extends Animal
    Declare Virtual Function S() Byref As String
End Type

Function Cat.S() Byref As String
    Static As String _S
    Return _S
End Function

Type Dog Extends Animal
    Declare Virtual Function S() Byref As String
End Type

Function Dog.S() Byref As String
    Static As String _S
    Return _S
End Function

Dim As String S0(...) = {"Animal", "Cat", "Dog"}


Dim As Animal Ptr p(...) = {New Animal, New Cat, New Dog}

For I As Integer = Lbound(p) To Ubound(p)
    p(I)->S = S0(I)
Next I

For I As Integer = Lbound(p) To Ubound(p)
    Print p(I)->S
Next I

For I As Integer = Lbound(p) To Ubound(p)
    Delete p(I)
Next I

Sleep
  • Code: Select all

    Animal
    Cat
    Dog
    
    ('Animal.S', 'Cat.S', and 'Dog.S' are well accessed sequentially)

The advantage of using virtual functions returning local static data by reference is that they can be manipulated with their names as static member data but for which runtime polymorphism would apply.
neil
Posts: 555
Joined: Mar 17, 2022 23:26

Re: polymorphism revisit - 2023

Post by neil »

I got this this example from DeepAI Chat.

Code: Select all

Type Animal
    Name As String
    Declare Function sound() As String
End Type

Type Dog
    Field As Function () As String
    Name As String
End Type

Type Cat
    Field As Function () As String
    Name As String
End Type

Type Bird
    Field As Function () As String
    Name As String
End Type

Function Dog_sound() As String
    Return "Woof"
End Function

Function Cat_sound() As String
    Return "Meow"
End Function

Function Bird_sound() As String
    Return "Tweet"
End Function

Sub PrintAnimalSound(MySoundFunction As Function () As String)
    Print MySoundFunction()
End Sub

Dim myDog As Dog
myDog.Field = @Dog_sound

Dim myCat As Cat
myCat.Field = @Cat_sound

Dim myBird As Bird
myBird.Field = @Bird_sound

PrintAnimalSound(myDog.Field)
PrintAnimalSound(myCat.Field)
PrintAnimalSound(myBird.Field)

Sleep
Here's another one.

Code: Select all

type Animal
    name as string
    declare sub speak()
end type

type Dog
    animal_func as sub
end type

type Cat
    animal_func as sub
end type

type Bird
    animal_func as sub
end type

sub Animal_speak()
    print "Animal speaks"
end sub

sub Dog_speak()
    print "Dog barks"
end sub

sub Cat_speak()
    print "Cat meows"
end sub

sub Bird_speak()
    print "Bird tweets"
end sub

dim as Dog myDog
myDog.animal_func = @Dog_speak

dim as Cat myCat
myCat.animal_func = @Cat_speak

dim as Bird myBird
myBird.animal_func = @Bird_speak


myDog.animal_func()
myCat.animal_func()
myBird.animal_func()

Sleep
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: polymorphism revisit - 2023

Post by fxm »

neil wrote: Feb 24, 2024 7:58 from DeepAI Chat.

What was the question asked because I do not see runtime polymorphism there because it manipulates objects declared (at compile time) of different types (the same as their constructors) ?

Runtime polymorphism makes it possible to treat objects of identical static type (that of their declarations) but of different dynamic types (those of their constructors) in the same way (without having any preconceptions about their dynamic types).
neil
Posts: 555
Joined: Mar 17, 2022 23:26

Re: polymorphism revisit - 2023

Post by neil »

@fxm I asked DeepAI for the Freebasic polymorphism animal code. So it's not polymorphism; it seems DeepAI is not always correct.
neil
Posts: 555
Joined: Mar 17, 2022 23:26

Re: polymorphism revisit - 2023

Post by neil »

@fxm DeepAI Chat claims this example is polymorphism.
How could I make changes to this example so it is true polymorphism?

Code: Select all

Type Animal
    dummy As Integer
    Declare Sub Speak()
End Type

Type Dog
    name As String
    Declare Sub Speak()
End Type

Type Cat
    name As String
    Declare Sub Speak()
End Type

Sub Animal.Speak()
    Print "I am an animal"
End Sub

Sub Dog.Speak()
    Print "Woof! My name is "; this.name
End Sub

Sub Cat.Speak()
    Print "Meow! My name is "; this.name
End Sub

Dim a As Animal Ptr
Dim d As Dog Ptr
Dim c As Cat Ptr

a = New Animal
d = New Dog
c = New Cat

a->Speak
d->name = "Buddy"
d->Speak
c->name = "Whiskers"
c->Speak

Sleep
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: polymorphism revisit - 2023

Post by Imortis »

Why on earth are you asking an AI to write code for something you don't understand? How are you supposed to debug it when it doesn't do what you intend? You would be better served learning what polymorphism is and then learning how to implement that in FB.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: polymorphism revisit - 2023

Post by caseih »

The AI wasn't totally wrong. The example is indeed a form of polymorphism, but it's static and resolved at compile time.

I get the impression, though that you are seeking for an example of dynamic or run-time polymorphism. This is where an abstract base class defines a common method (called a virtual method) that is implemented in derived classes. A working example of virtual methods and polymorphism is found in the docs:
https://www.freebasic.net/wiki/KeyPgVirtual

Since FreeBASIC is not a common language, the AIs are not going to know as much about it as the official docs do, I'm afraid.
neil
Posts: 555
Joined: Mar 17, 2022 23:26

Re: polymorphism revisit - 2023

Post by neil »

@Imortis I was looking for dynamic or runtime polymorphism.

You are correct. I need a better understanding of what polymorphism is.

The term polymorphism comes from:

"Poly" means many, and "morphism" details how something has the ability to change.

There are different types.
static or compile-time.
dynamic or runtime.

Parameteric (generic) polymorphism allows a routine to accept one or more type parameters, in addition to normal parameters, and runs itself on those types.

Subtype polymorphism allows a routine to act on any subtype of its parameters.

Ad hoc polymorphism generally uses routine overloading to grant polymorphic behavior, but can refer to other polymorphism implementations too.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: polymorphism revisit - 2023

Post by fxm »

neil wrote: Feb 26, 2024 22:57 @fxm DeepAI Chat claims this example is polymorphism.
How could I make changes to this example so it is true polymorphism?

Code: Select all

Type Animal
    dummy As Integer
    Declare Sub Speak()
End Type

Type Dog
    name As String
    Declare Sub Speak()
End Type

Type Cat
    name As String
    Declare Sub Speak()
End Type

Sub Animal.Speak()
    Print "I am an animal"
End Sub

Sub Dog.Speak()
    Print "Woof! My name is "; this.name
End Sub

Sub Cat.Speak()
    Print "Meow! My name is "; this.name
End Sub

Dim a As Animal Ptr
Dim d As Dog Ptr
Dim c As Cat Ptr

a = New Animal
d = New Dog
c = New Cat

a->Speak
d->name = "Buddy"
d->Speak
c->name = "Whiskers"
c->Speak

Sleep

Code: Select all

Type Animal Extends Object                     '' *****
    name As String                             '' *****
    Declare Virtual Sub Speak()                '' *****
End Type

Type Dog Extends Animal                        '' *****
    Declare Virtual Sub Speak()                '' *****
End Type

Type Cat Extends Animal                        '' *****
    Declare Virtual Sub Speak()                '' *****
End Type

Sub Animal.Speak()
    Print "I am an animal"
End Sub

Sub Dog.Speak()
    Print "Woof! My name is "; this.name
End Sub

Sub Cat.Speak()
    Print "Meow! My name is "; this.name
End Sub

Dim a As Animal Ptr
Dim d As Animal Ptr                           '' *****
Dim c As Animal Ptr                           '' *****

a = New Animal
d = New Dog
c = New Cat

a->Speak()
d->name = "Buddy"
d->Speak()
c->name = "Whiskers"
c->Speak()

Sleep
neil
Posts: 555
Joined: Mar 17, 2022 23:26

Re: polymorphism revisit - 2023

Post by neil »

@fxm Thank You!
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: polymorphism revisit - 2023

Post by fxm »

More generally, two types of polymorphism ("pseudo" or "real") are available with FreeBASIC, thanks to:
- Overloading => compile-time "pseudo" polymorphism
- Overriding => run-time "rea"l polymorphism

Overloading
Procedures (sub/function/operator) can be overloaded and the resolution is done thanks to the passed parameter signature (parameter type at compile-time).
The parameter passing can be explicit:

Code: Select all

Type Dog
    Dim As String name
End Type

Type Cat
    Dim As String name
End Type

Sub Speak Overload(Byref d As Dog)
    Print "Woof! My name is "; d.name
End Sub

Sub Speak Overload(Byref c As Cat)
    Print "Meow! My name is "; c.name
End Sub

Dim As Dog d : d.name = "Buddy"
Dim As Cat c : c.name = "Whiskers"

Speak(d)
Speak(c)

Sleep
or by extension implicit (hidden parameter by calling member procedure on objects):

Code: Select all

Type Dog
    Dim As String name
    Declare Sub Speak()
End Type

Type Cat
    Dim As String name
    Declare Sub Speak()
End Type

Sub Dog.Speak()
    Print "Woof! My name is "; this.name
End Sub

Sub Cat.Speak()
    Print "Meow! My name is "; this.name
End Sub

Dim As Dog d : d.name = "Buddy"
Dim As Cat c : c.name = "Whiskers"

d.Speak()
c.Speak()

Sleep
or mixed.

Overriding
In an inheritance structure, the override member procedure is called on an object depending on its run-time type (and not on its compile-time type which can be the same for all objects):

Code: Select all

Type Animal Extends Object
    Dim As String name
    Declare Abstract Sub Speak()
End Type

Type Dog Extends Animal
    Declare Virtual Sub Speak()
End Type

Type Cat Extends Animal
    Declare Virtual Sub Speak()
End Type

Sub Dog.Speak()
    Print "Woof! My name is "; this.name
End Sub

Sub Cat.Speak()
    Print "Meow! My name is "; this.name
End Sub

Dim As Animal Ptr p(1 To 2) = {New Dog, New Cat}
p(1)->name = "Buddy" : p(2)->name = "Whiskers"

p(1)->Speak()
p(2)->Speak()

Delete p(1) : Delete p(2)

Sleep


These articles I wrote in the Programmer's Guide might help about run-type polymorphism:
- Composition, Aggregation, Inheritance
- Inheritance Polymorphism
then, for a deeper knowledge (technical articles):
- OBJECT built-in and RTTI info
- Use Implicit / Overload New([]) and Delete([]) Operators with Inheritance Polymorphism
Post Reply