Oxygen Basic
Information => Open Forum => Topic started by: JRS on May 11, 2013, 02:14:40 PM
-
I would like to have an open discussion about the concepts of object-oriented programming and what it means. (to you) This thread isn't specific to any language. Any reference to language or code should only be used as an example, not how it should be done. I'm battling with the concept of inheritance and when it should be done. Should a class inherit another class just with only a reference to its name? Would this be considered embedded classes? Does it make more sense to create an object of a base class and do the inheritance at the object level rather than an application class that is per-constructed from base classes?
Object
In pure OOP terms an object is an instance of a class.
Inheritance
Ability of a new class to be created, from an existing class by extending it, is called inheritance.
I view OOP the same way I view a play. A play casts actors (objects) and is driven by a script and it's director. My goal with the ScriptBasic OOP implemtation is have dual interface to objects. A GUI based application would make callbacks to methods not requiring any interaction from the programmer other than instantiating them. There will be methods a class may contain that would only be called under programmer control. (utility, customization, ...) I'm defining the property of a method to be the function address. The programmer can also call the method as a function from the script.
-
Hi John,
OOP implementations come with a lot of conceptual baggage and cumbersome syntax, which has spoilt its reputation as a useful programming paradigm.
If OOP does not greatly simplify a programming task then, in my view, it should not be applied to it.
The most important feature of OOP is to remove hunks of variables and functions out of global space and put them onto their own independent islands, (commonly known as encapsulation).
This makes program merging much simpler, minimising name conflicts.
It also allows different classes of objects to have the same verb schema. For instance create, build, destroy, get, put, render, move, adjust, act, show, locate. This is an important aspect of so-called polymorphism.
For example a game may need to combine 2d controls, 3d objects, database, audio, and AI. Without OOP, combining these aspects into one project poses serious congestion of global name space and serious name bloat problems.
Inheritance turns out to be of lesser importance. And forcing classes into a false taxonomy, can spoil a program's architecture.
Charles
-
taxonomy
For the common people: nothing but CLASSIFICATION SCHEME.
-
Inheritance turns out to be of lesser importance. And forcing classes into a false taxonomy, can spoil a program's architecture.
What I'm having a hard time with is the inheritance tree. If you call a method of an object and that object has inherited methods with the same name, my understanding is the base class method is executed first and then the inherited methods in the order they were inherited. Same goes for properties.
Is this how you understand how inheritance works?
-
My understanding is that the new method overrides the inherited method, and that is how I have implemented it in Oxygen. Similarly if a variable is redefined, for instance: integer V becomes float V. Then the new V will be used.
Oxygen resolves inherited class members into a flat list (a single UDT), then scans this list in reverse order, when a class member is invoked. (This is not necessarily the best method to use in a scripted language.)
If these override are commonplace, that would indicate that the program design is flawed by trying to implement phoney inheritance.
-
This is a particulate inheritance and is nothing worth, it can inherit or it can not. :D
-
I think I confused myself with the internal (emulation) of inheritance and the bottom line is that the last inherited method/property has precedence. I then have to assume that once you inherit a method/property with the same name, dropping the child object doesn't restore it to it's previous state and would invalidate the base object. (inheritance is a one-way street) Correct?
-
Yes it is a one way system, like a family tree.
A derived class does not have any effect on its parent classes, but it would pass its overrides to any child classes derived from itself.
Thinking about a real application would help: for instance an accounts system supporting different kinds of ledger for small clients, corporate clients, suppliers, cash, hedge funds, off balance-sheet, bribes etc. They would all have common elements which could be aggregated to form useful base classes.
-
I'm trying to build a set of agreed upon rules. This is what I have so far. Please either approve or explain the errors of my ways.
- Objects are disposable code libraries created dynamically from class definitions.
- Inherited objects should only extend and not reduce/break existing functionality.
- Only base objects can be dropped/destroyed and classes have a shelf life as long as the application exists.
- Properties should only be modified by methods and never directly. (properties are known data repositories set/read with methods)
-
Hi John, I've hacked your list rather ruthlessly, I think it was strongly influenced by COM, which is a highly specific form of OOP.
Here is my take:
- Objects are created using class definitions, and generally take the form of compound-variables.
- Classes can specify references to procedures known as methods, and variables known as properties.
- Classes can inherit other classes and extend or modify the inherited functionality.
- Objects and classes may have restricted scope and duration.
- Generally, object properties are accessed by method call, not directly, so that their internal code can be altered without breaking programs that already use them.
-
Structural relationships:
types--->compound-types----------------
\
Classes
/
variables--->expressions--->functions---
-
Some Possible classes:
no properties or methods
class zen
end class
properties only
class point
float x,y,z
end class
methods only
class ops
method add(sys a,b) as sys
return a+b
end method
method sub(sys a,b) as sys
return a-b
end method
end class
-
With my POOP conversion I running into what I guess is called Method Overloading. This is where a method based on it's argument count and type(s) call multiple (sub-classed) functions. SB has no problems with overloaded functions but this overloaded method idea is hard to swallow. I ran into a helpful OOP reference I thought I would share.
Introduction to Object Oriented Programming Concepts (OOP) and More (http://www.codeproject.com/Articles/22769/Introduction-to-Object-Oriented-Programming-Concep)
@Charles: Is your e-mail not working? I have sent you numerous e-mails and not one reply. I'm thinking your e-mail server is rejecting them when that spam e-mail was sent from my account.
-
Hi John,
Thanks. That was a very detailed and very useful article. I liked much of it, with the exception of the C code examples, the general appearance and notation of which, is always a turn off. Nonetheless the article covers a very wide field, and is a good reference just to get the OOP concepts and lingo.
One of my reasons for concentrating on graphics at this time is that it demands modularisation OOP in a very concrete way, and is a rich test model to work with.
Sorry about the email. I'm on an email abstinence course for a few days to clear my head space. :)
Charles.
-
I'm on an email abstinence course for a few days to clear my head space.
I'm just happy you got them and there isn't some technical reason. Please have a look at them when you have some free time. I'm buried in trying to create the framework for a POOP alternative. POOP is an emulation that is very resource intensive and pushing the interpreter to limits it was never intended to support. It takes 50 MB (2 copies of the interpreter) just to bring up a customer maintenance screen with the POOP version of SAGE MAS (http://na.sage.com/sage-100-erp) accounting software. I'm guessing ScriptBasic will be able to do the same in under a MB.
-
After wading through the POOP, I have made a few design decisions that I think resolve the issues, maintain the intended business logic and allow continued use a language everyone already knows.
- When SB loads it's object modules (class definition files) a default/initialized object structure is created and ready to be instantiated. Creating the new instance is really nothing more than making a copy of the base object structure and assigning it a reference ID that is uses by all other SB object external access directives.
- All object instance properties and methods may be dynamically changed at runtime under programmer control or through inheritance.
- A NEW() directive can include inherited base classes which will create the instance structures for them as well.
- I have elected NOT to support method overloading as defined in POOP. SB will support function overloading as it's already built into the language design. This means adding a few more methods with extended names. It consolidates existing function overloading to one definition.
I'm still in the proof of concept phase but things so far are looking pretty good.
-
I can see how you use arrays to hold structures, but how do you implement a method in SB?
-
I can see how you use arrays to hold structures, but how do you implement a method in SB?
Methods are stored in a mixed element/associative array structure as an ADDRESS to the function. The function (method) may be resident to the base class or the ADDRESS changed by inheritance (or programmer) to point to the inherited class base object function. All property/methods would know by their instance count what level of the object structure it's suppose to be referencing.
Here is a snippet of code from a class I'm currently working on.
_OBJ[0]{"INFO"}{"OBJ_NAME"} = "SY_Session"
_OBJ[0]{"INFO"}{"OBJ_COUNT"} = 0
_OBJ[0]{"INFO"}{"ON_CREATE"} = "REQUIRED"
_OBJ[0]{"INFO"}{"ON_DELETE"} = "REQUIRED"
_OBJ[0]{"PROPERTY"}{"Caption$"}{"VALUE"} = ""
_OBJ[0]{"PROPERTY"}{"Caption$"}{"SET"} = "ERR"
_OBJ[0]{"PROPERTY"}{"PathCompany$"}{"VALUE"} = ""
_OBJ[0]{"PROPERTY"}{"PathCompany$"}{"SET"} = "ERR"
_OBJ[0]{"PROPERTY"}{"PathUser$"}{"VALUE"} = ""
_OBJ[0]{"PROPERTY"}{"PathUser$"}{"SET"} = "ERR"
_OBJ[0]("PROPERTY"}{"PathSystem$"}{"VALUE"} = ""
_OBJ[0]("PROPERTY"}{"PathSystem$"}{"SET"} = "ERR"
_OBJ[0]("PROPERTY"}{"PathHome$"}{"VALUE"} = ""
_OBJ[0]("PROPERTY"}{"PathHome$"}{"SET"} = "ERR"
_OBJ[0]("PROPERTY"}{"PathBase$"}{"VALUE"} = ""
_OBJ[0]("PROPERTY"}{"PathBase$"}{"SET"} = "ERR"
_OBJ[0]("PROPERTY"}{"PathRoot$"}{"VALUE"} = ""
_OBJ[0]("PROPERTY"}{"PathRoot$"}{"SET"} = "ERR"
_OBJ[0]{"PROPERTY"}{"UserGroupList$"}{"VALUE"} = ""
_OBJ[0]{"PROPERTY"}{"UserGroupList$"}{"FNGET"} = ADDRESS(GET_USR_GRPS())
_OBJ[0]{"PROPERTY"}{"UserGroupList$"}{"SET"} = "ERR"
...
_OBJ[0]{"METHOD"}("Logon"} = ADDRESS(USER_LOGON())
_OBJ[0]{"METHOD"}("InitiateUI"} = ADDRESS(START_UI())
_OBJ[0]{"METHOD"}("TerminateUI"} = ADDRESS(STOP_UI())
_OBJ[0]{"METHOD"}("InitiateWinAPI"} = ADDRESS(START_WINAPI())
_OBJ[0]{"METHOD"}("LaunchProgram"} = ADDRESS(LAUNCH())
_OBJ[0]{"METHOD"}("LogonAdmin"} = ADDRESS(LOGON_ADMIN())
_OBJ[0]{"METHOD"}("LogonFromFile"} = ADDRESS(LOGON_FROM_FILE())
_OBJ[0]{"METHOD"}("OpenSessionFiles"} = ADDRESS(OPEN_SESSION_FILES())
_OBJ[0]{"METHOD"}("CloseSessionFiles"} = ADDRESS(CLOSE_SESSION_FILES())
_OBJ[0]{"METHOD"}("WriteRegistryStartupEntries"} = ADDRESS(WRITE_REGISTRY_SETUP_ENTRIES())
-
Got it! Thanks John.
One thought occured to me: associative array indexes are quite expensive. For high performance, it might be better to use numeric indices, using variable names instead of the quoted names. All you will need is an equate list for all properties and methods.
-
The expense is on creation. Once the structures are created, SB accesses them rather efficiently as they just element based arrays under the covers. The other issue with MAS is that properties and methods use the $ for string variables (remember POOP is emulated OOP) and I have to maintain the naming otherwise this would be a rewrite. (thousands of lines of code spanning over 30 years)
-
There was this note in the user manual, (following the main description of associative arrays):
The typical use of associative arrays is to get a feature like record in PASCAL or struct in language C. Note that this type of storage is less than optimal in case it is used for a huge number of keys and values.
Searching the keys in the array is linear. It means that accessing a single element needs time proportional to the size of the array.
-
The class definitions are rather small so it should work just fine. I really have no other options in this case. Speed isn't the most important factor with this project and has been traditionaally an interpreter driven product.
I created an associative based object array that had 46 element definitions. I copied that structure 1000 times. (simulating instantiating an object) This time included loading SB from the command line.
jrs@laptop:~/sb/sb22/test$ time scriba asstest.sb
Object Instance Count: 1000
real 0m0.082s
user 0m0.064s
sys 0m0.020s
jrs@laptop:~/sb/sb22/test$
Time to execute a single PRINT statement.
jrs@laptop:~/sb/sb22/test$ time scriba print.sb
real 0m0.003s
user 0m0.000s
sys 0m0.000s
jrs@laptop:~/sb/sb22/test$
-
If a programmer creates an class that is meant to be inherited, should that sub-class / child be able to be instantiated on its own?
-
I think so.
The child class will inherit all the structural definitions and method references of its parents and add to them.
Javascript objects are quite interesting. They are a simplified form of OOP where there is no formal definition of classes.
http://www.w3schools.com/js/js_objects.asp
https://developer.mozilla.org/en/docs/JavaScript/Guide/Working_with_objects
Objects inherit directly from 'Object prototypes'
I think JavaScript OOP is closer to what you are doing in SB than compiler-based OOPs, where types and classes are formally defined.
-
I think JavaScript OOP is closer to what you are doing in SB than compiler-based OOPs, where types and classes are formally defined.
My goal with the SB OOP direction is to make it fully scriptable[possible new word] at runtime just as DLLC makes API access/Threading/Callbacks a dynamic scriptable interface. I view SB as the core object that everything else is a child of and using a traditional BASIC syntax for flow and structure.
The child class will inherit all the structural definitions and method references of its parents and add to them.
That wasn't my question. I wanted to know if a object that was designed to be inherited can be instantiated as a base object. (not as inherited) From what I have been able to dig up, any object instantiated should not have to depend on external (assumed as inherited) resources.
-
Yes, you can instantiate with base classes. Abstract classes are the ones which cannot be instantiated. (I have not tried deploying them yet)
-
Javascript objects are quite interesting. They are a simplified form of OOP where there is no formal definition of classes.
JavaScriptBasic is designed on a simple object-based paradigm. An object is a collection of properties, and a property is an association between a name and a value. A value of property can be a function, which is then known as the object's method.