OOP Syntax

For everything that's not in any way related to PureBasic. General chat etc...
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

yeah, afterwards i saw fsw's way :-)

i don't understand why you would need the 'newobject' thing

i mean, if the preprocessor runs into a yet unknown variable / object name, and sees it's type is a class, it would simply create an object belonging to that class, ie. no need for the 'newobject' statement, now is there?

you don't do a NewVariable l.l or something similar i think :-) or do i miss something?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
mp303

Post by mp303 »

Personally I think it would be a good idea to do something that more closely resembles existing OOP languages - and for any existing syntax, don't reinvent, but match existing PB syntax.

I liked Kale's example best so far, but with some minor changes.

Code: Select all

Class Contact
   Protected Name.s 
   Protected Address.s 
    
   Procedure SetName(Text.s) 
      Name.s = Text.s 
   EndProcedure 
    
   Procedure GetName.s() 
      ProcedureReturn Name.s 
   EndProcedure 

   Procedure SetAddress(Text.s) 
      Address.s = Text.s 
   EndProcedure 
    
   Procedure GetAddress.s() 
      ProcedureReturn Address.s 
   EndProcedure 
    
   Procedure Display.s() 
      ProcedureReturn GetName() + " : " + GetAddress() 
   EndProcedure 
    
   Constructor Contact(newName.s) 
      Name.s = newName
      Address.s = "" 
   EndConstructor
EndClass

Class PhoneContact Extends Contact
   Protected TelephoneNumber.s 
    
   Procedure SetTelephoneNumber(Text.s) 
      TelephoneNumber.s = Text.s 
   EndProcedure 
    
   Procedure GetTelephoneNumber.s() 
      ProcedureReturn TelephoneNumber.s 
   EndProcedure 

   Procedure Display.s() 
      ProcedureReturn GetName() + " : " + GetAddress() + " : " + GetTelephoneNumber() 
   EndProcedure 
EndClass 

Person.PhoneContact

Person\SetName("Charlotte the Harlott") 
Person\SetAddress("22 Acacia Avenue") 
Person\SetTelephoneNumber("666") 
Debug Person\Display()
Remarks:

Class MY_CLASS() - why the paranthesis? They don't seem to carry any information or functionality.

The destructor, I think you can forget about - it's going to be hard to enforce, e.g. keeping track of all created objects, and forcing any remaining objects to destroy when the application terminates. May not be easy. Might be simpler to just let users add their own "Procedure Destroy()" if they need one, since basically the compiler will probably rely on them to remember to destroy everything manually in the first place - thus perhaps not much in implementing a designated way to do it.

NewObject ... - why not simply "New", like in most other languages? For that matter, as long as you're only creating one, explicit object, as in your example, why not declare it in the same way you declare structures and variables in PB normally? This would also enable syntax-checking at compile-time, e.g. with no runtime overhead.

Other thoughts:

Support for multiple constructors. This way, I can create two constructors for "Contact", for example - one with the name parameter, one without.

And one problem: if this is to be done as a layer on top of PB, not natively in PB, how will debugging features be preserved? For example, how will you correlate an error in line 50 to a line in your original OOP source code?
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Post by Kale »

Class MY_CLASS() - why the paranthesis? They don't seem to carry any information or functionality.
To pass variables on object creation etc.

Code: Select all

Class Contact(Name="Default", Address="Default")
   Protected Name.s
   Protected Address.s
   
   Procedure SetName(Text.s)
      Name.s = Text.s
   EndProcedure
   
   Procedure GetName.s()
      ProcedureReturn Name.s
   EndProcedure

   Procedure SetAddress(Text.s)
      Address.s = Text.s
   EndProcedure
   
   Procedure GetAddress.s()
      ProcedureReturn Address.s
   EndProcedure
   
   Procedure Display.s()
      ProcedureReturn GetName() + " : " + GetAddress()
   EndProcedure
   
   Constructor Contact(newName.s)
      Name.s = newName
      Address.s = ""
   EndConstructor
EndClass

NewObject Me.Contact("Kale", "Here, there and everywhere")
Me.Display()
--Kale

Image
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

NewObject ... - why not simply "New", like in most other languages?
Cause "New" in c++ for example is not only class specific you can also heap alloc types and arrays of types.
Support for multiple constructors. This way, I can create two constructors for "Contact", for example - one with the name parameter, one without.
IIRC ... PB 4 allows giving predifined values to parameters in the arguments of a function if these are not prived by the call. So this can be done within the constructor by the user individually:

Code: Select all

Procedure Car::Car(brand.s="")
  if brand
    ...
  else
    ...
  Endif
Endprocedure
Like a little dumb boolean based overloading ;)


@ Kale
I think if a method gots the same name like its class then its really logic that the parser could see that one as a contructor - I do agree. Edels OOP-Plugin imho handles it like that.
But then also here a new command like Constructor isnt really needed imho.
NewObject Me.Contact("Kale", "Here, there and everywhere")
Also nice.


@Blueznl
i don't understand why you would need the 'newobject' thing

i mean, if the preprocessor runs into a yet unknown variable / object name, and sees it's type is a class, it would simply create an object belonging to that class, ie. no need for the 'newobject' statement, now is there?
I think there must be a way for the parser to recognise if an object will be constructed. Cause a symply MyObject.TheClass could be seen as simply allocating a given structure "TheClass" to the variable "MyObject" .... .
Its also like we do use "Dim" MyArray.l(5)
As simple MyArray.l(5) also wont be recognised corr. by the PB Compiler as a construction of an array. ;)
Check out OOP support for PB here!
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

inc. wrote:
ENABLEOOP and DISABLEOOP are not C++ keywords.
Jupp for shure not but as nomen-est-omen they do really make sense as its a parser these do got their function in ... guess what ;)
The longer I think about this my conclusion is: Not needed...
This is because the parser looks at every beginning of a line anyhow if he finds something to work with, like Class or EnableOOP.

So every line is parsed, you can't skip a single one.

Or am I missing something?
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

inc. wrote:Ok, Datasections do make it easier, but why that NewArray Way?
Can be changed back to DIM.
Thought that for PB users it would make sense because there is already NewList for Linked Lists and with NewObject beeing used for Class Objects NewArray for Arrays would make sense...
inc. wrote: What about this?
; Example 1: A single obj

Code: Select all

MYTHING.iMYOBJECT = New_MYOBJECT()
Don't see a benefit over this:

Code: Select all

Global NewObject myThing.MyObject
Wanted to keep the code as close to PB as possible.

inc. wrote: ; Example 2: An array of objs

Code: Select all

Dim AnotherThing.iMYOBJECT(5)
For i = 0 To 5
    AnotherThing(i) = New_MYOBJECT()
    AnotherThing(i)\GetVal(i)
    AnotherThing(i)\ShowVal()
Next i
The generation of an array of objs could be easely implemented in your parser so the follwoing would be possible

Code: Select all

NewObject myThing.MyObject(5)

For i = 0 To 5
    myThing(i)\GetVal(i)
    myThing(i)\ShowVal()
Next i
Excuse my ignorace, but why would somebody need that?

At first sight it seems to open new possibilities, ...but is it at the cost of simplicity?

Explain please.
Thanks
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

So, kale, is it me or do you begin to like oop? Or see the idea :)
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

fsw wrote:The longer I think about this my conclusion is: Not needed...
This is because the parser looks at every beginning of a line anyhow if he finds something to work with, like Class or EnableOOP.

So every line is parsed, you can't skip a single one.

Or am I missing something?
Nope, afterwards makes absolutely sense to me. ;)

Ok, Datasections do make it easier, but why that NewArray Way?
Can be changed back to DIM.
Thought that for PB users it would make sense because there is already NewList for Linked Lists and with NewObject beeing used for Class Objects
No, you didn't understand me, I meant why do u use for defining the object ..

Code: Select all

...
EndDataSection : Global NewArray MYOBJECT_Self.MYOBJECT(0)
; End of class

; Define Object
ReDim MYOBJECT_Self.MYOBJECT(0) : MYOBJECT_Self(0)\VTable = ?MYOBJECT_VTable : Global MYTHING.MYOBJECT_Methods = MYOBJECT_Self(0) ;THIS IS A COMMENT 
instead of a Constructor like in the code I did post above:

Code: Select all

Procedure.l New_MYOBJECT()
    Protected *obj.cMYOBJECT
    *obj = AllocateMemory(SizeOf(cMYOBJECT))
    *obj\VTable = ?MYOBJECT_VTable
    ProcedureReturn *obj
EndProcedure 
So ... you dont need the new object to be in a global state at all.
So its up to the user if he writes
NewObject MYTHING.iMYOBJECT or
NewObject *MYTHING.iMYOBJECT or
Global NewObject MYTHING.iMYOBJECT

inc. wrote: What about this?
; Example 1: A single obj

Code: Select all

MYTHING.iMYOBJECT = New_MYOBJECT()
Don't see a benefit over this:

Code: Select all

Global NewObject myThing.MyObject
Wanted to keep the code as close to PB as possible.

...

Excuse my ignorace, but why would somebody need that?
Explain please.
Again a misunderstanding ;)
These examples above where used in the native PB syntax approach.
For shure in your Parser the syntax should be kept as it is:
NewObject MYTHING.iMYOBJECT

And for an Array of objects you could ad an option for supporting this:
NewObject MYTHING.iMYOBJECT(5)


The idea is .... if your parser founds an "NewObject Mything.iMYOBJECT" he automatically ads to the "resulted PB-native output-code" the call of the constructor when defining the object like I posted some lines further above ;) like ... NewObject MYTHING.iMYOBJECT will be interpreted by the parser as MYTHING.iMYOBJECT = New_MYOBJECT() ; calling the constructor

and NewObject MYTHING.iMYOBJECT(5) will become in the resulted PB-native code ...

Code: Select all

Dim MYTHING.iMYOBJECT(5)
For i = 0 To 5
    MYTHING(i) = New_MYOBJECT()
Next i

Im talking about this option as beside other things I sometimes do convert small C++ Source-Parts to PB and the last one was a WaveFilePlayer where in the C++ Sources a WaveBuffer object was defined as

cWaveBuffer * myWaveBuffer = new cWaveBuffer[5]

PS: Also it would be a personal little "gusto" id such a parser could support a simple stringreplacement from "->" to "" (in non quoted parts ;) ) so the user could decide if he uses

Procedure Classname:MethodName(a.l)
*this\res = *this\b + a
Endprocedure

or

Procedure Classname:MethodName(a.l)
*this->res = *this->b + a
Endprocedure

I dont want to change PB to a C++ like syntax noooo, but in this case of OOP support its just a little addon.
Last edited by inc. on Sun Jun 04, 2006 12:34 am, edited 2 times in total.
Check out OOP support for PB here!
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Post by Kale »

thefool wrote:So, kale, is it me or do you begin to like oop? Or see the idea :)
I've programmed using OOP for years in Python and a little bit in C++. OOP is nothing new to me and it can have its ups and downs. But OOP in Purebasic??? i can't see it, maybe for v5 or v6 in a few years? but I would prefer Purebasic to stay BASIC. If you want OOP you can move to another language, there are plenty of them. :wink:
--Kale

Image
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

ok :)
Well,
stay BASIC
; many basics can use classes.. Many basics are actually OOP, and Is purebasic really a basic?
But of course there ought to be room for everybody's opinions. But; would it really hurt PB that much?
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

But OOP in Purebasic???
Remember this Thread doesnt try to again beg fred for integrating OOP capabilities into PB as these are already given when using the workouts which can be seen in the native-PB code outputs of such Plugs.
These Plugs just make these needed code-workouts to be handled easier.

Shure, someday somebody could rise and tries to release his total different syntax (like Klingon Syntax ;) ) realised by a PB Preprocessor. Like that type of xxxBasic (dont know the name now) which does translate the xxxBasic syntax to C before being processed by the C compiler.

Code: Select all

Machpach(0,1023,398,"Elam mer at",#PB_VeratExem)
Er nom > 1024
  Braktmegun(0, "Brakta")
Elra
  Braktmegun(0, "Ukutam")
Firem
;)
But thats what such diskussions like this one are supposed to be: Trying to keep things for the community non-chaotic
Check out OOP support for PB here!
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Things like javascript manage to provide both approaches, so as long as Pure kept the Pure approach as well, OOP would not be a problem to users.

However, the Pure team is small and there are other things need doing which are way ahead in priority (disclaimer: IMHO).

Aside: Maybe one of those priorities would be to make it easy to use libs and dlls written in C++ so we could throw away the agonising need for writing/finding wrappers for these things. Not an easy task, but then writing something like Pure is not easy, and the Pure team is pretty darn clever.

I think OOP can be implemented by users, via preprocessor.

A kick-ass preprocessor for Pure would surely be saleable.

Also, a kick-ass preprocessor would IMO have:

* An oop-aware IDE (at least)
* Syntax that was obviously oop - not necessarily too Pure-ish (but not necessarily overly or obsfucatingly Oop-ish either). In fact, it would need to be different enough from Pure so as to not cause confusion by being too similar (being a pre-processor it is going to convert, anyway).


Again: Just MHO
Dare2 cut down to size
remi_meier
Enthusiast
Enthusiast
Posts: 468
Joined: Sat Dec 20, 2003 6:19 pm
Location: Switzerland

Post by remi_meier »

EnableOOP just speeds up things like:

Code: Select all

a = 5 : Class Test : p.l = 5 : EndClass
And you could use the new keywords outside EnableOOP/DisableOOP as
variables.

And for the NewObject approach with the arrays in the output disables
a use of objects in a linked list AFAIK. For me, something like

Code: Select all

obj.CLASS = new CLASS(5, 4)
delete obj

NewList LL.CLASS()
AddElement(LL())
LL() = new CLASS(3, 4)

Dim AA.CLASS(20)
AA(0) = new CLASS(1, 2)
Would be ideal. CLASS(1, 2) calls the constructor with the parameters 1,2.
Athlon64 3700+, 1024MB Ram, Radeon X1600
mp303

Post by mp303 »

Dare wrote:I think OOP can be implemented by users, via preprocessor.
How would you do debugging?

I'm not trying to shoot down your idea, but I just don't see how that's supposed to work - if an error occurs in line 30 in the intermediary output from the preprocessor, the PB debugger will say the error occurred in line 30. But what if line 30 was generated by line 20 in the preprocessor code?

Hmm, I guess the preprocessor would have to generate a log file that says which line number in the preprocessor code generated which line number in the intermediary ... because we can't expect users to manually try to figure this out, especially in large programs, can we?
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

at least here i may have a suggestion: the pre processor could spawn a window showing a two column listing of the code, left the original, right the processed one (before it's passed on to the compiler)

as for line numbers, that's tricky, what one should try to do is avoid synchronization errors, for example those lines that are expended into multiple lines could be fixed by putting multiple commands on the same line using : (colons?) whilst those that would end up with less lines could have some empty lines added to them
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Post Reply