Dim Byref syntax

For other topics related to the FreeBASIC project or its community.
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 8:28

With pointers we do exactly the same thing. First we declare the type and the pointer is null. Then we assign the pointer to some reference. Every programmer values that kind of flexibility. Instance identifiers are basically just pointers so why forcing them to always point to an instance?
fxm
Posts: 9554
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Dim Byref syntax

Postby fxm » Nov 27, 2018 8:44

In FreeBASIC, one can reconstruct an already existing object, by explicitly call the wished constructor on its instance name (as any member procedure).
Warning, depending on field data of the Type (UDT), it can be mandatory to call the destructor first:
Dim As UDT u [ = UDT(parameters) ]
...
[ u.Delete() ]
u.Constructor(other_parameters)
...
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 8:49

Here is an actual example from the BASIC Studio project. The function presents the user with a Save File dialog and depending on the user's choice the action may be completed or aborted. If aborted there is no point in having a FolderItem object in which case a null object would be much better. Now the object is created no matter with all inherent overhead as a result:

Code: Select all

function GetSaveFolderItem overload(byref t as TFileTypes) as TFolderItem
   dim d as TFileDialog ' PREFERABLY dim d as new TFileDialog
   dim f as TFolderItem ' NULL OBJECT PREFERABLY
   
   d.Title = kSaveFile
   d.Action = GTK_FILE_CHOOSER_ACTION_SAVE
   d.Create()
   d.FileTypes(t)
   
   if d.Show = GTK_RESPONSE_ACCEPT then
      f = TFolderItem(d.FileName) ' NEW INSTANCE PREFERABLY
   end if
   
   d.Destroy
   return f ' INSTANCE OR NULL UPON RETURN PREFERABLY
end function
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 8:58

fxm wrote:In FreeBASIC, one can reconstruct an already existing object, by explicitly call the wished constructor on its instance name (as any member procedure).
Warning, depending on field data of the Type (UDT), it can be mandatory to call the destructor first:
Dim As UDT u [ = UDT(parameters) ]
...
[ u.Delete() ]
u.Constructor(other_parameters)
...

Yes, I'm aware of that but it is inefficient if there is no need for a default copy.
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 9:19

Here is a quick, working example of what currently is supported by FreeBASIC regarding null objects:

Code: Select all

#define unref(o) delete @(o)
#define newobj *new
#define nil(o) @(o) = 0
#define nilref(o) *cptr(o ptr, 0)
#define nilobj(o) o = nilref(o)
#define obj(o) byref o
#define ref(o) @(o)

type TFolderItem extends object
   filename as string
   folder as string
   ' etc...
end type

function GetSaveFolderItem() byref as TFolderItem
   dim obj(f) as nilobj(TFolderItem)
   dim confirmed as boolean = false
   
   if confirmed then
      ref(f) = ref(TFolderItem())
   end if
   
   return f
end function

dim obj(f) as nilobj(TFolderItem)

ref(f) = ref(GetSaveFolderItem())
if not nil(f) then
   ' save the file
   print "file saved"
else
   print "file not saved, action aborted."
end if
Despite all declarations, not a single (FolderItem) object is actually created if the action is canceled. Change the boolean inside the function to see the difference.
coderJeff
Site Admin
Posts: 3170
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Dim Byref syntax

Postby coderJeff » Nov 27, 2018 13:39

@Munair, in your example, add a constructor/destructor to TFolderItem() with some print statements to see: ref(f) = ref(TFolderItem()) creates a temporary instance only for the expression. fbc doesn't know that a reference is being bound. But, if it did, and it was persistent at this point, then need a unref(f) later to pair up the new/delete.

Null reference problems look a lot like pointer problems. Having truly NULL references, that point to zero address, and must not be dereferenced, seems like trouble. To make it safe, then we would be checking for null references on every use of a reference. Which to me seems inefficient. Either the user must to it, or the compiler has to automatically add the check.

But, something like dim byref variable as DataType = Nothing needs only assign a reference (internally a pointer), so no cost for construction. To bind an object to this reference, like what you are doing with *new more is needed to track the lifetime of the object, what fbc currently does not have capability for with the very simple OBJECT object.

@fxm,
changelog.txt wrote:- ASM backend: Fix bad code generated for comparisons such as IF @globalvar = 0 THEN
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 13:53

coderJeff wrote:@Munair, in your example, add a constructor/destructor to TFolderItem() with some print statements to see: ref(f) = ref(TFolderItem()) creates a temporary instance only for the expression. fbc doesn't know that a reference is being bound. But, if it did, and it was persistent at this point, then need a unref(f) later to pair up the new/delete.

I already checked this with a constructor and it appears, it is not called when the function returns a null object. So this seems to work. Here is the same working code with a constructor:

Code: Select all

#define obj(o) byref o
#define asobj byref as
#define newobj *new
#define ref(o) @(o)
#define unref(o) delete ref(o)
#define nil(o) ref(o) = 0
#define nilref(o) *cptr(o ptr, 0)
#define nilobj(o) o = nilref(o)

type TFolderItem extends object
   filename as string
   folder as string
   ' etc...
   declare constructor()
end type

declare function GetSaveFolderItem() asobj TFolderItem

constructor TFolderItem()
   print "default constructor called"
end constructor

function GetSaveFolderItem() asobj TFolderItem
   dim obj(f) as nilobj(TFolderItem)
   dim confirmed as boolean = false
   
   if confirmed then
      ref(f) = ref(TFolderItem())
   end if
   
   return f
end function

dim obj(f) as nilobj(TFolderItem)

ref(f) = ref(GetSaveFolderItem())
if not nil(f) then
   ' save the file
   print "file saved"
else
   print "file not saved, action aborted."
end if

coderJeff wrote:fbc doesn't know that a reference is being bound. But, if it did, and it was persistent at this point, then need a unref(f) later to pair up the new/delete.

It wouldn't hurt to call unref(f) in all cases, but I wonder if it is not absolutely necessary, even if nil(f) would be false. This is because the object instance returned by the function comes from a null object that is referenced afterwards; it is not created with the NEW keyword.
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 14:14

coderJeff wrote:But, something like dim byref variable as DataType = Nothing needs only assign a reference (internally a pointer), so no cost for construction. To bind an object to this reference, like what you are doing with *new more is needed to track the lifetime of the object, what fbc currently does not have capability for with the very simple OBJECT object.

Perhaps in the future, to extend FB's OOP capabilities, the CLASS keyword could be used so that support for the current extended object with UDT's remains unbroken. That way class instances could be supported whereby the programmer is totally responsible for instantiating objects (as it should be), while easier programming could be done using object Types. Class example:

Code: Select all

class MySubClass
   public:
      s as string
      declare constructor()
end class

constructor MySubClass()
   s = "my sub class"
end constructor

class MyClass
   public:
      mys as MySubClass
   declare constructor()
end class

constructor MyClass()
   mys as new MySubClass
end constructor

dim myc as new MyClass

print myc.mys.s

' auto destruction of instances
end
I realize that such implementation would be tremendous work, although some compiler code providing object Types might also be used to support Classes. The current problem with FB when developing large projects is that nested objects (they can be many) are all created at the same time, which is an unnecessary drain on performance and resources.
St_W
Posts: 1484
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Dim Byref syntax

Postby St_W » Nov 27, 2018 14:27

Munair wrote:[...] whereby the programmer is totally responsible for instantiating objects (as it should be) [...]
In FB you have full control over the lifecycle of an object, much more than in common OO languages.
Most languages nowadays try to relief the programmer from managing the object's lifecycle themselves. They often provide a garbage collector that automatically frees memory when it is not used anymore. Garbage collection can indeed cause performance issues and does use quite some additional resources (depending on the used technique). In contrast manual memory management, like you have to do it in FB (because the compiler doesn't provide anything else), doesn't cost a lot of resources at all. I can't really explain the performance issues you mentioned because allocating objects on the stack is very cheap, maybe the real reason for that is something else?
dodicat
Posts: 6360
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Dim Byref syntax

Postby dodicat » Nov 27, 2018 15:03

Munair.
I like to run your code, but without having to compile -pp beforehand.
What is the definition of a null object?
It doesn't have to have an actual value of zero?
If it has a value (address) which nothing occupies or can possibly occupy, then is that a null object?

Code: Select all

type udt
    as string s1,s2="HI"
end type


dim byref as udt f= *cast(udt ptr,-1)


print @f

'f.constructor '<------  existence test

dim as udt z
@f=@z
print f.s2

sleep
 
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 15:09

St_W wrote:
Munair wrote:[...] whereby the programmer is totally responsible for instantiating objects (as it should be) [...]
In FB you have full control over the lifecycle of an object, much more than in common OO languages.
[/quote]I beg to differ. Control means that you can determine when objects are instantiated. With nested objects that is currently not possible with FB. Individually they can neither be instantiated, null referenced nor deleted. The only workaround is the direct use of pointers.[/quote]
St_W wrote:Most languages nowadays try to relief the programmer from managing the object's lifecycle themselves. They often provide a garbage collector that automatically frees memory when it is not used anymore. Garbage collection can indeed cause performance issues and does use quite some additional resources (depending on the used technique). [..] I can't really explain the performance issues you mentioned because allocating objects on the stack is very cheap, maybe the real reason for that is something else?

Allocating objects is one thing, invoking the constructors along with them is another; everything of an object is initialized. Therefore, especially with large projects it is very much desired to have control over when nested objects are instantiated (and their constructors called). I would very much like to see support for null references with nested objects and reference/initialize and delete them when needed.
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 15:18

dodicat wrote:Munair.
I like to run your code, but without having to compile -pp beforehand.
What is the definition of a null object?
It doesn't have to have an actual value of zero?
If it has a value (address) which nothing occupies or can possibly occupy, then is that a null object?

It is very much like a pointer of a specific type. Upon declaration a pointer points to nothing, but its type is declared. Instance identifiers are pointers to class/object structures. When objects are instantiated, a copy of the object structure is created and the instance identifier points to that copy, which allows access to its members. However, unlike with pointers to simple types, when a reference/instance is created, the (default) constructor is called along with everything that needs to be initialized. With complex objects, a lot can happen behind the scenes, like memory allocation and member (child object) initializations.

You should be able to compile the working examples without -pp. By default here on Geany I compile only with -w all.
St_W
Posts: 1484
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Dim Byref syntax

Postby St_W » Nov 27, 2018 15:22

Munair wrote:I beg to differ. Control means that you can determine when objects are instantiated. With nested objects that is currently not possible with FB. Individually they can neither be instantiated, null referenced nor deleted. The only workaround is the direct use of pointers.
That's what I meant. You instantiate it with "new" and delete it with "delete". You can nest those as you like. Using pointers is not a "workaround" - it's the way how it's meant to be done. You should not compare apples with oranges: if you're talking about objects that live on the stack in FB you should compare them to value types in object-oriented langues, which can't be nulled and do have the same restrictions there.

I can understand your wish to allow syntactic constructs in FB similar to other OO languages you know, but the semantics are often a bit different in FB although the syntax looks similar. FB is much more similar to C++. (and whether that is good or bad is a different question ...)
Last edited by St_W on Nov 27, 2018 15:28, edited 1 time in total.
dodicat
Posts: 6360
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Dim Byref syntax

Postby dodicat » Nov 27, 2018 15:28

Munair
I can compile your code OK, but to read it I have to get yourcode.pp.bas
I am unable to mentally inline you macros without incurring a headache.
Munair
Posts: 886
Joined: Oct 19, 2017 15:00
Location: 't Zand, NL
Contact:

Re: Dim Byref syntax

Postby Munair » Nov 27, 2018 15:29

St_W wrote:
Munair wrote:I beg to differ. Control means that you can determine when objects are instantiated. With nested objects that is currently not possible with FB. Individually they can neither be instantiated, null referenced nor deleted. The only workaround is the direct use of pointers.
That's what I meant. You instantiate it with "new" and delete it with "delete". You can nest those as you like.

This will never compile nor execute because one is not allowed to touch the child reference:

Code: Select all

type tOne extends object
   s as string
   declare constructor()
end type

constructor tOne()
end constructor

type tTwo extends object
   s as string
   One as TOne
   declare constructor()
end type

constructor tTwo()
   One = new tOne
   delete One
end constructor

dim two as tTwo

Return to “Community Discussion”

Who is online

Users browsing this forum: No registered users and 5 guests