October 06, 2022, 09:29:34 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Uninitialized variable: DemoDTP - CDTP WARNING

Started by Allan, November 16, 2008, 06:39:34 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Allan

November 16, 2008, 06:39:34 PM Last Edit: November 16, 2008, 06:49:32 PM by Allan
Having problem understanding what is wrong with this project when compiled as it shows a WARNING?

QuoteCompiling...
Main.eba
File: C:\My EBasic Forum\DTP\Main.eba (35) Warning: Uninitialized variable: DemoDTP - CDTP
CDTP.eba

Thought I had done it 'by the book'.

The RECT does not draw either?      DemoDTP.DrawObject()

Allan

Ionic Wind Support Team

The warning is normal and can be ignored.

The compiler generates warnings when it doesn't see a local variable being initialized before it has been used for the first time.  Unfortunately it doesn't know that classes don't need to be initialized so it will always generate that warning.

If you were to create the class with NEW then your wouldn't get the warning.


SUB CDTP::SetWindow(window win)
win = win
ENDSUB


What did you thing that would do?   Scope resolution is local->class->global.  So all the statement win=win is doing is copying the local parameter over itself.  If you really wanted to copy the whole window structure you could use the 'this' pointer:


SUB CDTP::SetWindow(window win)
*<CDTP>this.win = win
ENDSUB


And while that would make your class work, it would be poor practice.  Name your class variables something a little more unique, such as using m_win, and that way you'll instantly recognize that it is a member variable of the class.

A better design would be to use a pointer, instead of a window UDT.  Only requires a couple of changes:


CLASS CDTP
DECLARE CDTP()
DECLARE SetWindow(window win)
DECLARE DrawObject()
PROTECTED
WINRECT m_DRect
        POINTER m_win
ENDCLASS



' CDTP.eba

$INCLUDE "CDTP.inc"

SUB CDTP::CDTP()
m_DRect.left = 10
m_DRect.top = 10
m_DRect.right = 180
m_DRect.bottom = 120
        m_win = NULL
ENDSUB

SUB CDTP::SetWindow(window win)
m_win = win
ENDSUB

SUB CDTP::DrawObject()
        IF m_win
    RECT #<WINDOW>m_win, m_DRect.left, m_DRect.top, m_DRect.right, m_DRect.bottom,  RGB(255,155,0), RGB(100,0,255)
        ENDIF
ENDSUB


Keep cracking at it, and be sure to study the object oriented programming section of the users guide.

http://www.ionicwind.com/guides/emergence/language_topics_oop.htm

Thanks,
Paul.
Ionic Wind Support Team

LarryMc

Allan
You never told it to draw.

SUB MakeDemo(),INT
DEF DemoDTP as CDTP
DemoDTP.SetWindow(Main)
DemoDTP.DrawObject()
RETURN 0
ENDSUB


Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Allan

OK - Thanks. I thought I would pass Main in from the Main Window to the Class.

Also can you put another Class into a Class as a Member of the class.

BRIEFLY...

CLASS one
  declare one()
PROTECTED
  winrect a
ENDCLASS

CLASS two
  declare two()
  one xone  ' other class
PROTECTED
  winrect b
ENDCLASS

Allan

LarryMc

Quotecan you put another Class into a Class as a Member of the class.
I don't think so but I might be wrong
A class member is a variable of some type and not a "function/subroutine"
A class method is the "function/subroutine"

I know you can create multiple classes and use a class inside of another class.

Maybe someone else that understands it better can explain it better.

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Allan

Yes - I have changed the code and it works as expected.

Though I have tried putting second class in as member.
Should it not hold the complete class and have access?

Attached the updated CDTP with second class.

I have used this in other langs (CBuilder) and thought it may work in EB?

Allan

Ionic Wind Support Team

A class member can be any variable type, including another class.  As long as that class has been defined before use of course.

Have you read the users guide section?

Paul.
Ionic Wind Support Team

Allan

QuoteHave you read the users guide section?

More times than I can count!  But that does not mean I get the message correct.

Originally I was hung up on the misunderstanding of this:
QuoteAccess protection

It is generally considered bad form to directly access a member variable from outside of a method implementation. In the above examples we have been setting the name of the employee directly using a dot operator.
To aid in limiting outside access to an objects data Emergence provides three keywords, PUBLIC, PRIVATE and PROTECTED that control how an objects methods and members may be used.

I was trhing to access the Methods out of SCOPE for them.

SCOPE was the problem I had first try and again this time.

Now I got it in my head that SCOPE has to be observed for the different Instances of a CLASS.  The Circles Protected Members were not accessible from where I was trying to use them!

Have re-done the DTP again and attached it.

Please have a look at the code and any suggestions would be most welcome.

regards,
Allan


Ionic Wind Support Team

Of course I have suggestions.  Which is why I asked if you had read the section on OOP programming.  I could kind of see where you were heading when you fist posted your code.

Instead of one class that has member variables of other classes, you should experiment and learn about virtual methods and inheritance.  I hesitate to write the code for you, as OOP is something that is best learned hands on. 

Think of a design that uses a base class, perhaps called CDTPObject, which has virtual methods named SetParams and Draw, you then derive from the base class overriding those methods with the ones in the derived classes.

Class CDTPObject
    Declare SetWindow(pointer win)
    Declare Virtual SetParams(pointer obj)
    Declare Virtual Draw(pointer win)
End Class

Class CDTPRect, CDTPObject
    Declare Virtual SetParams(pointer obj)
    Declare Virtual Draw(pointer win)
...
End Class

Class CDTPEllipse, CDTPObject
    Declare Virtual SetParams(pointer obj)
    Declare Virtual Draw(pointer win)
...
End Class

This is just to give you ideas and inspiration.  Method overriding and inheritance are the primary reason to write an application using OOP instead of a straight procedural implementation.  Objects that share similar properties should have an abstract base class that can be derived from.  GUI libraries commonly employ this technique, using a base "window" class that all other objects are derived from.  Which gives the advantage of not needing to know what kind of object is drawing, the application using the GUI objects call the virtual methods Draw, Move, Resize, etc and the correct method for the particular object gets called.

Objects like this work best when created dynamically.  So for sake of discussion lets say we were using a GUI library whose base class was called GWindow, and there were derived classes called GButton, GMenu, and GToolbar.  In our imaginary application we have a subroutine that draws all objects contained in a linked list, and those objects were created by another subroutine...


SUB CreateInterface
pointer obj
   obj = NEW(GWindow,1)
   #<GWindow>obj.Create(100,100,100,100)
   ListAdd(gList,obj)
   obj = NEW(GButton,1)
    #<GButton>obj.Create(10,10,50,20,"Close")
   ListAdd(gList,obj)
   obj = NEW(GMenu,1)
   #<GMenu>obj.AddTitle("File")
   #<GMenu>obj.AddItem("Quit")
   ListAdd(gList,obj)
ENDSUB

SUB DrawEverything(pointer list)
pointer obj
   for obj = each list as GWindow
       #obj.Draw()
   next
ENDSUB


In the DrawEverything subroutine we don't need to know the class of the object in order to draw it, because all objects are derived from a common base class and 'Draw' is a virtual method.

Your current method will work, and there is nothing wrong with it of course, so if it makes you happy then go with it.  When you get a bit more comfortable then try using base and inherited classes.  One step at a time.

Paul.
Ionic Wind Support Team

Allan

QuoteOf course I have suggestions.....

Those suggestions are great and I will take them to heart and use them as shown.

There is just one more thing to get my head around in that project and it is saving to file.

I wish to use that technique of VIRTUAL Functions to Write and Read to a File from the LinkedList, the same way you have done the DRAW.

Thank you Paul.

Allan

DTP4 now has Derived Classes and Virtual Methods as suggested by Paul in above message...

This was a very educational task and helped me see more clearly into CLASS structure. I have been using Classes for years (pre-built ones that is) but have not been actually building many of my own Classes.

Actually doing the coding helps learn!

Experiment . . .
I tried to make the CDTPEllipse Class Derive from the CDTPRect Class so as to use the Members already defined in the CDRect Class. They are the same Members. Help File - EB would need to have more than one level of inheritance to handle that I guess?

After finishing the Program I realised that the m_win could have been handled in the OBJECTS that were passed to the SetParm Method instead of having its own Method [SetWindow(pointer win)] which is used as well in its Derived Classes (CDTPRect, CDTPEllipse, CDTPCircle).

But the way it is shows the Classes at work using Methods of a Base Class as well as the VIRTUAL Methods in the Derived Classes.

I can see ways to extend the program using LineStyle and Brush Style and other effects. It will keep me bizzy for a while!

EB Classes are very neat!!

Thanks for your help, Paul and Larry.

Please have a look at the code and any suggestions would be most welcome.

Allan


LarryMc

Been following what Allan is doing and trying to make sense of it all.

There's one part in particular that I'm just not getting an handle on.

Allan is creating objects from different classes and storing a pointer to each in a linked list.
Then there is thisSUB DrawEverything(pointer list)
pointer obj

for obj = EACH list AS CDTPObject
#obj.Draw()
NEXT

ENDSUB

He's going through the list with typecasting as the basec class CDTPObject
I don't understand what is triggering the calling of the CORRECT derived class.

Is it purely an internal windows thing that I should accept that that's the way it works 'just cause'?

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Ionic Wind Support Team

Virtual functions ensure the correct method is called.  That is the purpose of them, and it has to do with how OOP works.  Nothing to do with Windows at all.

Every instance of a class object has a vtable (virtual function table), basically an array of addresses to subroutines.  When you declare a method as virtual:

class SomeClass
declare virtual Draw()
end class

The vtable would have 1 address in it, the address of SomeClass::Draw()

When you derive a class and override the virtual function:

class AnotherClass, SomeClass
declare virtual Draw()
end class

The vtable element has the address of AnotherClass::Draw(), in other words it replaced the address of SomeClass::Draw in that array.

A pointer is generic when you think about it, it just contains an address.  So if you have:

#<SomeClass>p.Draw()

And p actually contains a pointer to AnotherClass then the vtable ensures the correct method gets called.  Much like a function pointer:

!<Draw>p.vtable[0]()

So a virtual method is called by the compiler by looking up the address in the vtable, while a non virtual method is called directly.  If Allan had not used the "virtual" keyword when declaring the methods then the line #obj.Draw() would only call CDTPObject::Draw().

Emergence BASIC, and Aurora use a vtable mechanism identical to C++, which is why we can use Emergence Classes to create COM servers.  So you could search the net for a better description of virtual functions and the vtable, but most are confusing to non C++ users.

In Emergence, like in C++ the address of the vtable is stored in the first member of the class instance, it is kind of like a hidden variable.  Consider this code:


class SomeClass
declare virtual Draw()
declare virtual Erase()
end Class

sub SomeClass::Draw()
endsub

sub SomeClass::Erase()
endsub

def class1 as SomeClass


We create a class, implement two virtual methods, and define a variable of that class.  If you look at the assembly output, towards the end, you will see the vtable:


SomeClass_vtable_
dd $SomeClass@Draw
dd $SomeClass@Erase

segment .bss use32 align=4
$class1 resb 4


Which is the array of address I mentioned.  Now lets add a derived class:


class AnotherClass,SomeClass
declare virtual Draw()
end Class

sub AnotherClass::Draw()
endsub

def class2 as AnotherClass


When compiled and you examine the assembler output then you'll see the vtable of AnotherClass:


SomeClass_vtable_
dd $SomeClass@Draw
dd $SomeClass@Erase


AnotherClass_vtable_
dd $AnotherClass@Draw
dd $SomeClass@Erase


Since we only overrode the Draw method the AnotherClass vtable has AnotherClass::Draw as its first address and SomeClass::Erase as it's second address.  Which means if you don't override a method then the base class version will be called.

Paul.

Ionic Wind Support Team

LarryMc

Paul
That's an excellent explanation of virtual methods.

But you know how I am.
To me, vtables are a "windows thing" ;) and the answer I really understand is:

QuoteIs it purely an internal windows thing that I should accept that that's the way it works 'just cause'
;D

Thanks

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Allan

For anyone interested in this programs development I have now added File Save and File Load Virtual Methods to the Class.

Also have taken out the Method of Setting the Window m_win Member as it is only needed for Drawing the Graphics and can be passed through the Draw Virtual Method.

The SaveFile Method was easy and really only a copy of the Draw Virtual Method.

The ReadFile Method was not as simple so if anyone can see how to contain it more into the CLASS lets know please.

Any Suggestions are welcome?

The Code is Attached.

Allan

Allan

DTP6

Using CLASSES in EBasic has made it easy to simply add new Members and Methods to the existing project.

We have added two more Members to the Rectangle, Ellipse and Circle Classes.  They are LineWidth and LineStyle.
LineWidth is only used for the SOLID LineStyle as other LineStyles only use LineWidth of 1.

The Two New members are added to the Derived Class Definitions. The necessary changes to the Methods have been done in the CDTP.eba file. The Constructors needed two additional members set.:-
m_LineWidth = 1
m_LineStyle = "@LSSOLID"

The SetParam Methods had two new Members set.:-
m_LineWidth = #obj.LineWidth
m_LineStyle = #obj.LineStyle

WriteFile Methods required two new code lines:
WRITE #gf, m_LineWidth
WRITE #gf, m_LineStyle

ReadFile Methods required two new code lines:
READ(#gf, m_LineWidth)
READ(#gf, m_LineStyle)


The Virtual Draw Methods also had to be changed so as to select the correct LineStyle and LineWidth to draw the Graphic with.

The UDT for each Graphic Object had to have the two new members put in them also. The UDT for the Objects is now in a file by itself, namely "udts.inc".  The reason for doing that is they are needed in two other Graphic Input Dialogs now in the Program.

The two new dialog windows are - 1: For Rectangle and Ellipse Input data; 2. Circle Input data.

In the Main Program window there are now Vertical and Horizontal Scrollbars.  The scrollbars are used to scroll a second window (gwin) which is a child of the Main window and is used to draw the Graphic Objects onto instead of drawing them onto the Main Window.

A Toolbar has been added with images for Text, Rectangle, Circle, Ellipse. Text is not yet set into the CLASS as a Derived Class. The other Buttons in the Toolbar are active and will display a Dialog allowing the entry of the parameters for the graphics.

These graphics created in the Dialogs are then stored into the Linked List and drawn on the new gwin Window.

The Save and Load File methods now use a Dialog Window to choose the File to Load or Save.

A lot of the code has been taken from EBasic Sample programs and other users contributions on the Forum.

Allan