Author Topic: About Constructors and Destructors  (Read 794 times)

0 Members and 1 Guest are viewing this topic.

Josť Roca

  • Sr. Member
  • ****
  • Posts: 263
About Constructors and Destructors
« on: September 27, 2018, 10:50:13 PM »
Hi, Charles,

If I'm not wrong, it seems that Constructors and Destructors are only called automatically if you use NEW / DEL, contrarily to FreeBasic, in which you can call Constructors with DIM and objects created with DIM call the Destructor when they go out of scope. Am I right?

This particularity of FreeBasic is very convenient beause you can have procedures with parameters declared AS <classname> and pass values accepted by the Constructors. It creates temporary objects that destroy themselves. Same when  using the class name to return a value as a result of a function.

Is there a way to do it with O2?


Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3980
    • Oxygen Basic
Re: About Constructors and Destructors
« Reply #1 on: September 28, 2018, 02:02:26 AM »
in o2 objects, constructors and destructors are optional, and only invoked automatically with new and del, which are currently implemented as macros.

But it is feasible with a few simple changes in the compiler. The word temp might be used to denote that the object's destructor is to be internally called at the end of local/global scopes. Would this be satisfactory?

Josť Roca

  • Sr. Member
  • ****
  • Posts: 263
Re: About Constructors and Destructors
« Reply #2 on: September 28, 2018, 02:41:59 AM »
Let me try to explain it.

Suppose that I have a class called CVAR that implements support for Variants. This class has constructors with different parameters, such string and numbers.

If I have a procedure like

SUB Foo (BYREF cv AS CVAR)

I can call it as Foo "Test string"

The compiler will create a temporary instance of the CVAR class and call the constructor that accepts an string. When  the SUB ends and that temporary CVAR goes out of scope, it calls the destructor of the class.

Otherwise, we will have to do something like

DIM cv AS  NEW CVAR = "Test string"
Foo cv
DEL cv

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3980
    • Oxygen Basic
Re: About Constructors and Destructors
« Reply #3 on: September 28, 2018, 07:53:51 AM »
It's a novel construct to me, but I should be able to weave it into the tapestry quite easily.

There is a large procedure for polymorphic function matching, and it will convert primitive parameters when it can't find a function with matching params. I can extend this to generate the new/del statements required for transient objects.

Josť Roca

  • Sr. Member
  • ****
  • Posts: 263
Re: About Constructors and Destructors
« Reply #4 on: September 28, 2018, 08:21:26 AM »
This feature, together with operator overloading and casting as allowed me to implement datatypes not supported by FreeBasic that almost behave as native datatypes, e.g. CWSTR (Dynamic unicode null terminated string), CBSTR (BSTR datatype), CVAR (variants), CPropVar (PropVariants), CCUR (Currency), CDEC (Decimal), CInt96 (96 bit integers), CSafeArray (Safe arrays). And then, thanks to having support for these datatypes, clases like CSTack(Stacks), CQueue (Queues), CDicObj (associatetive arrays), CDispInvoke (Automation wrapper), CWmiDIsp (WMI), and many more.

Also, when returning an instance of these classes as the result of a function or method, FreeBsic does the following:

Code: [Select]
FUNCTION Foo () AS CWSTR
   DIM cws AS CWSTR = "Test string"
   FUNCTION = cws
END FUNCTION

When using FUNCTION =, it creates a temporary instance of the class and calls the appropriate LET operator (if it is not implemented, it won't work correctly), that will copy the contents, and returns the temporary CWSTR, that will self destroy once it is assigned to the variable that receives the result.

Code: [Select]
FUNCTION Foo () AS CWSTR
   DIM cws AS CWSTR = "Test string"
   RETURN cws
END FUNCTION

When using RETURN, it will do the same but calling the appropriate constructor, i.e. if the class has a constructor that accepts a string, you can do:

Code: [Select]
FUNCTION Foo () AS CWSTR
   RETURN "Test string"
END FUNCTION

It is a pity that some features like dynamic unicode strings risk to never be implemented because of platform differences, i.e. Windows uses UTF-16 and Linux UTF-8.
« Last Edit: September 28, 2018, 08:28:54 AM by Josť Roca »

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3980
    • Oxygen Basic
Re: About Constructors and Destructors
« Reply #5 on: September 28, 2018, 07:13:14 PM »
Thanks, Josť,

This is possible in o2. (the pointer is returned explicitly)

Code: [Select]
FUNCTION Foo () AS CWSTR
   'DIM cws AS CWSTR = "Test string"
   'FUNCTION = cws
   NEW CWSTR cws("Test String")
   FUNCTION=@cws
END FUNCTION

FUNCTION Foo () AS CWSTR
   'DIM cws AS CWSTR = "Test string"
   'RETURN cws
   NEW CWSTR cws("Test String")
   RETURN @cws
END FUNCTION

'CWSTR cws1 at foo()
DIM cws1 as CWSTR PTR : @cws1=foo()
...
DEL cws1

Josť Roca

  • Sr. Member
  • ****
  • Posts: 263
Re: About Constructors and Destructors
« Reply #6 on: September 28, 2018, 08:38:49 PM »
Well, not exactly the same. The CWSTR returned by FreeBasic is temporary (self-destroying), so you can do:

FUNCTION Foo1 () AS CWSTR
SUB Foo2 (BYREF cws AS CWSTR)

Foo2 Foo1

and don't have memory leaks.

Josť Roca

  • Sr. Member
  • ****
  • Posts: 263
Re: About Constructors and Destructors
« Reply #7 on: September 28, 2018, 09:20:04 PM »
With FreeBsic you can create instances of a class in two ways: using NEW and using DIM. Using NEW works like in O2, i.e. you have to destroy the class with Free (FreeBasic) or Del (O2). When using NEW with FreeBasic, you have to use the pointered syntax to call the methods of the class, i.e. p->method_name. When using DIM, it returns a reference, you use the doted syntax, i.e. p.method_name, and the class destroys himself when the reference goes out of scope.

Using NEW is more efficient regarding speed, because no copy operation is performed. Using DIM is more easy to use because you don't have to worry about freeing the class, and more flexible because you don't have to use intermediate steps.

Using NEW I can't do Foo2 Foo1 because the pointer returned by Foo1 won't be freed. I wil have to do

DIM cws1 as CWSTR PTR : @cws1=foo()
Foo2 cws1
Del cws1

Josť Roca

  • Sr. Member
  • ****
  • Posts: 263
Re: About Constructors and Destructors
« Reply #8 on: September 28, 2018, 09:47:07 PM »
Using references has also the advantage that we can have arrays of a given class and each element of the array will self-destroy when the array is freed.

For example, I can do.

Code: [Select]
DIM rg(1 TO 10) AS CWSTR
FOR i AS LONG = 1 TO 10
   rg(i) = "string " & i
NEXT

and also

REDIM PRESERVE / ERASE

Code: [Select]
REDIM rg(0) AS CWSTR
rg(0) = "string 0"
REDIM PRESERVE rg(0 TO 2) AS CWSTR
rg(1) = "string 1"
rg(2) = "string 2"
print rg(0)
print rg(1)
print rg(2)
ERASE rg

without having to worry about freeing each and every one of the pointers stored in the array as I will have to do if I used NEW.

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3980
    • Oxygen Basic
Re: About Constructors and Destructors
« Reply #9 on: September 29, 2018, 02:51:09 AM »
o2 has a system for creating higher type operations. Since it is macro-based, it does not require OOP, so you can get higher performance, and less complexity at the binary level.

However, I need to add a protocol for converting between different types transparently, which would satisfy your foo functions.