Bringing more object orientation to C programming

This forum is for general developer support questions.

Bringing more object orientation to C programming

Postby TSK » Sun Apr 02, 2017 4:53 pm

I've started a project to bring more object style programming to plain C and Amiga, after I figured out how to use APICALL trick to add function calls to C struct's. I've made a oo.library (oo for object orientation) which contains all New...Object() and Dispose...Object() function calls to create objects based on internal classes of the library. All the rest is handled through the objects themselves. The classes will initialize all of the internal variables properly, all the allocations and freeing is done on your behalf, opening and closing everything is done for you. The oo.library opens and closes all necessary OS libraries and OS classes for you. The idea is coding is simplier, faster development, writing less code is needed and coding is safer for newbies and lazy programmers leading to more bug free software hopefully. The classes takes care of all the low level stuff on your behalf.

The base is Toolobj object/class. (I chose the name because Application library and Utility library exists already. But I don't think a Tool library exists.) The Toolobj object takes care of signal waiting and events handling calling your events handler functions. The tool object takes care of opening and closing a language catalog as well. And some more.

The window class contains a LoadGUI method to read a GUI definition from a file. I'm calling it GUI Markup Language, which follows Reaction programming directly. Or you can create a GUI creating the objects individually.

This whole project is far away from finished or anything useful and will require a lot of work.

Currently *partially* implemented classes are: Toolobj, Windowobj, Fileobj, Dirobj, Listobj, Nodeobj, Hookobj, Layout, Button, Stringgadget, Label, Networkobj, Clipobj (clipboard).

Examples:
Code: Select all
BOOL Quit=FALSE;

int32 HandleAppIconEvents(struct Hook *hook, WINDOWOBJ *winobj, uint32 value)

{
 if (winobj!=NULL) { winobj->Uniconify(); }

} // HandleAppIconEvents


int32 HandleDockEvents(struct Hook *hook, WINDOWOBJ *winobj, uint32 value)

{

} // HandleDockEvents


int32 HandleMainWinEvents(struct Hook *hook, WINDOWOBJ *winobj, uint32 myclass)

{
 uint16 mycode=(uint16)(uint32)hook->h_Data;

 switch (myclass & WMHI_CLASSMASK)
 {
  case WMHI_CLOSEWINDOW: Quit=TRUE;
  break;

  case WMHI_ICONIFY: winobj->Iconify();
  break;

  case WMHI_UNICONIFY: winobj->Uniconify();
  break;

  case WMHI_GADGETUP:
   switch (myclass & WMHI_GADGETMASK)
   {
    case 1:
     printf("Gadget 1 clicked\n");
    break;

    case 2:
     Quit=TRUE;
    break;
   }
  break;
 }

 if (Quit) { return -1; } else { return 0; }
} // HandleMainWinEvents


int main(int argc, char **argv)
{
 struct Library *OOBase=(struct Library *)IExec->OpenLibrary("oo.library",1);
 if (OOBase!=NULL)
 {
  struct OOIFace *IOO=(struct OOIFace *)IExec->GetInterface(OOBase,"main",1,NULL);
  if (IOO!=NULL)
  {
   if (argc==0) // Launched from Workbench
   { TOOLOBJ *tool=(TOOLOBJ *)IOO->NewToolObject("TestApp",TRUE,(struct WBStartup *)argv); }
   else // Launched from CLI/Shell
   { TOOLOBJ *tool=(TOOLOBJ *)IOO->NewToolObject(argc[0],TRUE,NULL); }
   if (tool!=NULL)
   {
    tool->AddAppEventHandler(HandleAppIconEvents);

    BUTTON *but1=(BUTTON *)IOO->NewButtonGadgetObject(1,TRUE,tool->GetCatalogStr(1,"Ok"),FALSE);
    BUTTON *but2=(BUTTON *)IOO->NewButtonGadgetObject(2,TRUE,tool->GetCatalogStr(2,"_Cancel"),FALSE);
    if ((but1!=NULL) && (but2!=NULL))
    {
     LAYOUT *layout=(LAYOUT *)IOO->NewLayoutGadgetObject(0,LAYOUT_ORIENT_HORIZ);
     if (layout!=NULL)
     {
      WINDOWOBJ *mainwin=(WINDOWOBJ *)IOO->NewWindowObject(tool,"main");
      if (mainwin!=NULL)
      {
       mainwin->SetTitle("TestApp");
       mainwin->SetIconName("ram:TestApp");
       mainwin->EnableGadgets(TRUE,TRUE,TRUE,TRUE);
       mainwin->EnableIconifyGadget(TRUE);
       mainwin->SetWindowWidth(600);
       mainwin->SetWindowHeight(300);

       layout->AddObject(but1);
       layout->AddObject(but2);
       mainwin->SetLayout(layout); // An alternative way: mainwin->SetLayoutObject(layout->GetObject());
       // object->GetObject() will return a memory pointer to Intuition's Object* type of class/image/gadget object

       mainwin->Open();
       tool->AddWindowEventHandler(mainwin,HandleMainWinEvents);

       tool->Run(); // This one takes care of signal waiting and calling your HandleAppIconEvents() and HandleMainWinEvents() functions

       // It's time to quit...
       IOO->DisposeWindowObject(mainwin);
      }
      IOO->DisposeLayoutGadgetObject(layout);
     }
     IOO->DisposeButtonGadgetObject(but1);
     IOO->DisposeButtonGadgetObject(but2);
    }

    IOO->DisposeToolObject(tool);
   }

   IExec->DropInterface((struct Interface *)IOO);
  }
  else printf("TestApp ERROR: Can't open oo main interface\n");
  IExec->CloseLibrary(OOBase);
 }
 else printf("TestApp ERROR: Can't open oo.library v1\n");
}


Code: Select all
 struct Library *OOBase=(struct Library *)IExec->OpenLibrary("oo.library",1);
 if (OOBase!=NULL)
 {
  struct OOIFace *IOO=(struct OOIFace *)IExec->GetInterface(OOBase,"main",1,NULL);
  if (IOO!=NULL)
  {
   TOOLOBJ *tool=(TOOLOBJ *)IOO->NewToolObject("TestApp",TRUE,(struct WBStartup *)argv);
   if (tool!=NULL)
   {
    tool->AddAppEventHandler(HandleAppIconEvents);

      WINDOWOBJ *mainwin=(WINDOWOBJ *)IOO->NewWindowObject(tool,"main");
      if (mainwin!=NULL)
      {
       mainwin->SetTitle("TestApp");
       mainwin->SetIconName("ram:TestApp");
       mainwin->EnableGadgets(TRUE,TRUE,TRUE,TRUE);
       mainwin->EnableIconifyGadget(TRUE);
       mainwin->SetWindowWidth(600);
       mainwin->SetWindowHeight(300);

       mainLayout=mainwin->LoadGUI("TestApp.gui");
       if (mainLayout!=NULL)
       {
        mainwin->Open();
        tool->AddWindowEventHandler(mainwin,HandleMainWinEvents);

        tool->Run();

        // Time to quit...
       }
       else printf("TestApp ERROR: Couldn't load GUI ml\n");

       IOO->DisposeWindowObject(mainwin);
      }
     }
    }

    IOO->DisposeToolObject(tool);
   }

   IExec->DropInterface((struct Interface *)IOO);
  }
  else printf("TestApp ERROR: Can't open oo main interface\n");
  IExec->CloseLibrary(OOBase);
 }
 else printf("TestApp ERROR: Can't open oo.library v1\n");


The TestApp.gui file:
Code: Select all
<?guiml version="1.0"?>
<!DOCTYPE GUI>
<layout orientation="horizontal">
   <button id="1" label="Ok" catalogid="1" active="true" weightedwidth="100" weightedheight="0" />
   <button id="2" label="_Cancel" catalogid="2" active="true" weightedwidth="100" weightedheight="0" />
   <string id="3" active="true" maxchars="100" weightedwidth="0" weightedheight="0" />
</layout>
Keep the party going !
User avatar
TSK
Beta Tester
Beta Tester
 
Posts: 215
Joined: Mon Dec 20, 2010 2:15 pm
Location: Home land of Santa C., sauna, sisu and salmiakki

Re: Bringing more object orientation to C programming

Postby javierdlr » Mon Apr 03, 2017 12:39 am

Wohoo!! Looks very promising!!! Keep coding mate!!!! :-O
User avatar
javierdlr
Beta Tester
Beta Tester
 
Posts: 367
Joined: Sun Jun 19, 2011 11:13 pm
Location: Donostia (GUIPUZCOA) - Spain

Re: Bringing more object orientation to C programming

Postby trixie » Mon Apr 03, 2017 1:23 pm

@TSK

Code: Select all
IOO->NewToolObject("TestApp",TRUE,(struct WBStartup *)argv);
IOO->NewWindowObject(tool,"main");

Wouldn't it be much more convenient and future-proof to have just one constructor function for all objects, where the first parameter would be the object type and the other parameters would be type-dependent? Or, where the first parameter would be the object type and the second one would be a taglist in which you'd configure the object to be created?

If I were you, I'd scrap the entire oo.library stuff and build my system on top of BOOPSI. The Intuition Library already features the necessary constructor, destructor, getter and setter functions, so all you'd need to do is create a master class for whatever attributes/methods might be shared and inherited by your class set, and then develop the individual classes as subclasses of that master. Simple, elegant, using the tried-and-trusted BOOPSI infrastructure, and virtually no extra learning curve for the programmer because your classes would be manipulated as any other classes already in the system.

(There seems to be a common myth that BOOPSI is for GUI programming only. Take Reaction's ARexx Class, for example: it has no actual relation to GUIs yet it is BOOPSI. I'm currently developing an XML-parsing class, also within the BOOPSI framework. The sky's the limit.)
Smoke me a kipper, I'll be back for breakfast!
SAM440ep-flex @ 667MHz / 1GB RAM / Radeon 9250 / AmigaOS 4.1 Final Edition
User avatar
trixie
 
Posts: 351
Joined: Thu Jun 30, 2011 3:54 pm
Location: Czech Republic

Re: Bringing more object orientation to C programming

Postby broadblues » Mon Apr 03, 2017 3:09 pm

@TSK

Why not just use C++? It does pretty much everything you need without you spending ages revinventing the wheel, you don't have to use the more complex features if you want to keep things simpler.

Don't get me wrong, experimenting and creating something for yourself is a good way to learn stuff, but it just seems you really are heading down a psuedo C++ root so why not bite the bullet and go the whle way and learn C++?
Last edited by broadblues on Mon Apr 03, 2017 3:21 pm, edited 1 time in total.
User avatar
broadblues
AmigaOS Core Developer
AmigaOS Core Developer
 
Posts: 461
Joined: Sat Jun 18, 2011 3:40 am
Location: Portsmouth, UK

Re: Bringing more object orientation to C programming

Postby broadblues » Mon Apr 03, 2017 3:20 pm

trixie wrote:@TSK

Code: Select all
IOO->NewToolObject("TestApp",TRUE,(struct WBStartup *)argv);
IOO->NewWindowObject(tool,"main");

Wouldn't it be much more convenient and future-proof to have just one constructor function for all objects, where the first parameter would be the object type and the other parameters would be type-dependent? Or, where the first parameter would be the object type and the second one would be a taglist in which you'd configure the object to be created?


If each object requires a seperate constructor function, it's not really very object orientated, though it still might be more 'organised' than a completely functional approach.

If I were you, I'd scrap the entire oo.library stuff and build my system on top of BOOPSI. The Intuition Library already features the necessary constructor, destructor, getter and setter functions, so all you'd need to do is create a master class for whatever attributes/methods might be shared and inherited by your class set, and then develop the individual classes as subclasses of that master. Simple, elegant, using the tried-and-trusted BOOPSI infrastructure, and virtually no extra learning curve for the programmer because your classes would be manipulated as any other classes already in the system.


Interestingly AWeb took exactly this approach, except that it created it's own BOOPSI equivalent functions, NewAWebObject() etc etc not 100% sure why they chose to create duplicate functions, the core object was extremely BOOPSI like in structure, and could well have worked if everything was decended from "rootclass" . It might be that keeping it seperate from intuitions original avoided deadlocks with intuition as many class interacted with but were not part of the GUI, don't know the design history and decisions preceding my involvement.

(There seems to be a common myth that BOOPSI is for GUI programming only. Take Reaction's ARexx Class, for example: it has no actual relation to GUIs yet it is BOOPSI. I'm currently developing an XML-parsing class, also within the BOOPSI framework. The sky's the limit.)


One issue wirh BOOPSI approach is the relative inefficiency of it's message passing system. AWeb cheated occasionally because of that with a few direct accesses to the object data in very tight loops.
User avatar
broadblues
AmigaOS Core Developer
AmigaOS Core Developer
 
Posts: 461
Joined: Sat Jun 18, 2011 3:40 am
Location: Portsmouth, UK

Re: Bringing more object orientation to C programming

Postby TSK » Tue Apr 04, 2017 3:23 pm

@javierdlr
Nice to know somebody likes this.

@broadblues, @trixie
I started to make similar classes in C++ years ago. I remembered that I didn't make it far but I found the files from my HD and the project was pretty much on the same level as the C implementation is now. I've been programming mostly in C and DotNet (and few other languages) during many years and not using C++ much. I wanted to get C# like programming to Amiga and also to plain C as well. Also how do you compile C++ code into an Amiga library ? Is that possible and how ? Otherwise I would have to share the classes in source code form. Which is not necessarily a problem if I'm going to release it as freeware anyway but... It's possible to develop both versions together.

And the project is huge for a single person to work alone anyway. So I might to get this to some usable state or not ever. I implemented it all only that far to be able to create a working utility to see if the idea works at all in the end. I might stop here, redesing all or just continue.

Broadblues mentioned some limitations of BOOPSI. Intuition don't like some of its functions called from a BOOPSI class. When Intuition calls your dispatcher functions input and output seems to be locked for everybody else so you can't do any long time taking stuff because you would lock up the machine to the end user for too long time and eventually causing a dead lock with Intuition possibly. There's too many different Set...Attrs functions. Attributes are limited to uint32 ti_Data in struct TagItem. You have to convert memory pointers to uint32 and no chance to pass floats, for example. Intuition and input.device are too easy to crash. You have to use awkward IDoMethod() which is too easy to crash, as well. Like I said I want C# like coding.

I'm trying to stay away from BOOPSI and Intuition as much as I can. It's also Hyperion's responsibility to make higher level classes around all OS components. Especially I would like to see higher level classes around Timer, Clipboard and AHI devices. People are complaining against needing to download 3rd party libraries already so it all have to come as an official component in the OS. If AmigaOS had higher level and easier programming API I wouldn't have started my project. Except that I want to still have some C# like programming in plain C (*). AmigaOS dev team and Hyperion haven't been able to improve AmigaOS in many years, at least not trying to make it easier for us programmers and newbie programmers. I'm not expecting anything from them anymore. Amiga E mentions being object oriented but I don't know what that means exactly and E is imitating Pascal which I haven't used in over 25 years. Don't want to start learning Pascal again. Some kind of Amiga "C#" would be nice to have.

I was also thinking to make separate interfaces into the library for every object type. But forcing programmers to open several tens of interfaces would have been silly. I was thinking your suggestion to create "child" object through parent objects but I skipped that idea for some reason and decided make those constructor functions for every object type into the library. It's still good enough to pass the parent object to a new object when creating it. But I started to modify the code already where parent objects have those constructor functions. It's maybe a good idea doing it that way.

There's also oltck library on os4depot which hides signal waiting and timer device handling under a higher level API. It would be nice if something similar would be part of AmigaOS.
Last edited by TSK on Tue Apr 04, 2017 3:36 pm, edited 1 time in total.
Keep the party going !
User avatar
TSK
Beta Tester
Beta Tester
 
Posts: 215
Joined: Mon Dec 20, 2010 2:15 pm
Location: Home land of Santa C., sauna, sisu and salmiakki

Re: Bringing more object orientation to C programming

Postby TSK » Tue Apr 04, 2017 3:29 pm

* (I know you can get away typing interfaces using inlines. But...)

Which one is nicer to write while programming ? This one...
IIntuition->SetGadgetAttrs((struct Gadget *)GadObjs[GAD1],MyWindow,NULL,GA_Disabled,TRUE,TAG_DONE);

or this one...
mygad1->Disable();

;-)

AmigaOS API and programming was maybe good in 1980s. But it doesn't belong to 2010s.
Keep the party going !
User avatar
TSK
Beta Tester
Beta Tester
 
Posts: 215
Joined: Mon Dec 20, 2010 2:15 pm
Location: Home land of Santa C., sauna, sisu and salmiakki

Re: Bringing more object orientation to C programming

Postby broadblues » Tue Apr 04, 2017 4:46 pm

Broadblues mentioned some limitations of BOOPSI. Intuition don't like some of its functions called from a BOOPSI class. When Intuition calls your dispatcher functions input and output seems to be locked for everybody else so you can't do any long time taking stuff because you would lock up the machine to the end user for too long time and eventually causing a dead lock with Intuition possibly.


See ARExx class for why that's not entirely true, it's amatter of design, BOOPSI is a message based object orientated system, messages can be queued for later attention and don't (shouldn't even) be completely dealt with on the disptcers context.

Think typical window event loop, arexx event loop, etc. etc

It may not be ideal for your purposes, but don't underestimate it :-)
User avatar
broadblues
AmigaOS Core Developer
AmigaOS Core Developer
 
Posts: 461
Joined: Sat Jun 18, 2011 3:40 am
Location: Portsmouth, UK

Re: Bringing more object orientation to C programming

Postby TSK » Thu Apr 06, 2017 2:47 pm

broadblues wrote:messages can be queued for later attention

I wasn't talking of queuing messages but running long taking CPU intensive tasks in functions. Actually I was talking quite a lot and not any single case of anything.
Keep the party going !
User avatar
TSK
Beta Tester
Beta Tester
 
Posts: 215
Joined: Mon Dec 20, 2010 2:15 pm
Location: Home land of Santa C., sauna, sisu and salmiakki


Return to General Developer Support

Who is online

Users browsing this forum: Google [Bot] and 2 guests