Poster | Thread |
bison
| |
BOOPSI and OOP Posted on 19-Feb-2019 21:35:06
| | [ #1 ] |
|
|
|
Elite Member |
Joined: 18-Dec-2007 Posts: 2112
From: N-Space | | |
|
| This is a continuation of this interesting but off-topic subthread.
@Jupp3
Quote:
@bison
Quote:
Yes, I think this is right, and it always seems clunky to me. The leading "obj->" in "obj->DoSomething(obj, args)" is just syntactic sugar to make it look OO when it's really not.
|
I guess I am the opposite.
In my opinion, the fact that you have to do a very minor thing manually, doesn't make the approach any less "object oriented".
I assume you're one of those people, who claim you can't do object oriented coding in assembly language? |
I've never thought about it, but I guess I would be. I think of assembly language as a software representation of the Von Neumann architecture, and C as a higher level abstraction of the same.
Quote:
In my opinion, object orientedness is 99% "what / how coder decides to do", and less about any particular language features.
C++ especially makes it extremely easy to avoid any object orientedness if you want, while some other higher level languages try to enforce it on you more. |
I dislike C++ for its complexity, and Java because it is too much of an OO straight jacket. I also have concerns about Java's performance, but that's another matter.Last edited by bison on 19-Feb-2019 at 09:41 PM.
_________________ "Unix is supposed to fix that." -- Jay Miner |
|
Status: Offline |
|
|
Jupp3
| |
Re: BOOPSI and OOP Posted on 19-Feb-2019 22:02:49
| | [ #2 ] |
|
|
|
Super Member |
Joined: 22-Feb-2007 Posts: 1225
From: Unknown | | |
|
| @bison
Quote:
I dislike C++ for its complexity |
One common argument for C++ is that it offers you a bunch of features, and you're free to choose which ones to use, and which ones to ignore.
I like that. I choose the "C subset". Why would I use C++ then? |
|
Status: Offline |
|
|
bison
| |
Re: BOOPSI and OOP Posted on 19-Feb-2019 23:26:10
| | [ #3 ] |
|
|
|
Elite Member |
Joined: 18-Dec-2007 Posts: 2112
From: N-Space | | |
|
| @Jupp3
Quote:
One common argument for C++ is that it offers you a bunch of features, and you're free to choose which ones to use, and which ones to ignore. |
Yeah. I've always used a subset, when I've used it at all.
I kind of like the "Better C" subset of the D programming language.
Better C_________________ "Unix is supposed to fix that." -- Jay Miner |
|
Status: Offline |
|
|
hth313
| |
Re: BOOPSI and OOP Posted on 19-Feb-2019 23:27:10
| | [ #4 ] |
|
|
|
Regular Member |
Joined: 29-May-2018 Posts: 159
From: Delta, Canada | | |
|
| C++ has several problems, one of them being that it is not well suited for stable link APIs, which makes it ill suited for anything like BOOPSI.
Quote:
Jupp3 wrote:
I like that. I choose the "C subset". Why would I use C++ then? |
In most cases you are probably better off using something else than C++.
|
|
Status: Offline |
|
|
matthey
| |
Re: BOOPSI and OOP Posted on 19-Feb-2019 23:51:29
| | [ #5 ] |
|
|
|
Elite Member |
Joined: 14-Mar-2007 Posts: 2393
From: Kansas | | |
|
| Quote:
I've never thought about it, but I guess I would be. I think of assembly language as a software representation of the Von Neumann architecture, and C as a higher level abstraction of the same.
|
Assembly language allows for the complete control of the computer unrestricted by any language. OOP programming is indeed possible but most assembly programmers are optimizing for performance instead of size. Indirect branches and/or communicating with multiple parent objects is not good for performance.
Quote:
I dislike C++ for its complexity, and Java because it is too much of an OO straight jacket. I also have concerns about Java's performance, but that's another matter.
|
Modern high performance hardware was dealing with C++ by using expensive in hardware indirect branch caches and aggressive speculative execution which turned out to be less of a good idea with Spectre. I expect C++ and Java compiled programs are more affected by Spectre fixes than C compiled programs. C has continued to be the most popular language on embedded hardware because of the performance, especially on low performance hardware lacking OOP accelleration.
OOP is supposed to be able to save code with the sharing and inheritance of objects but C++ programs are usually larger than C programs. There are less lines for programmers to code as more builtin functionality is included but there are plenty of free C libraries available too. BOOPSI is quite a different OOP design being built into the OS. I wonder how it compares in efficiency. It has been awhile since I looked for indirect branches. I do expect the modularity of Amiga shared libraries does a better job of saving code than trying to pull functions from a link library. Unused code is probably less likely to take up memory with Amiga libraries but most of the world doesn't care much about bloat, yet.
Last edited by matthey on 20-Feb-2019 at 12:00 AM.
|
|
Status: Offline |
|
|
Snorg
| |
Re: BOOPSI and OOP Posted on 20-Feb-2019 5:12:11
| | [ #6 ] |
|
|
|
Regular Member |
Joined: 1-Feb-2018 Posts: 117
From: Unknown | | |
|
| @matthey
Concerning performance and optimization, the programmer, being authoritative over the logic governing the domain of the application is, in principle, always in a better position to optimize than some pre-built delegate. Think global (e.g. link-time) optimization.
One inefficiency of modular programming resides in the isolation of algorithm contexts. If you have all of the source code for a build, the compiler can produce a more optimal binary. On the other hand, if everything exists in opaque units, the compiler has fewer opportunities to eliminate dead code, improve register allocation, reorganize loads and stores, etc.
In your code, you have to draw the line (many, many times). With the compiler, that line is blurred. Whether you think this is good or bad depends upon how well the compiler optimizes and how well you understand those optimizations.
So, by definition, there is a cost to incorporating static or shared binaries. But no reasonable person would suggest you don't use them. You make a decision, and sometimes that decision is made for you.
Similarly, there is a cost to partitioning logic into discrete objects.
A great example is the standard C++ library: powerful, but that power comes at a sizable cost. For me, when performance matters, it is too large a cost. But I still have all the C++ language features to use as I see fit.
For example, with inlined template functions, I can write a function with parameterized (expression-based) constants, one which calls other such functions. What would otherwise become a (more) complex call graph in the binary becomes a single unit of (more) highly optimized code - but the source code remains (essentially) familiar to those who like C.
There is a dichotomy at work. Less is more, but more is more, too, when necessary.
If you use polymorphism, you will incur overhead. Still, sometimes it is the best option.
|
|
Status: Offline |
|
|
Hypex
| |
Re: BOOPSI and OOP Posted on 20-Feb-2019 16:15:17
| | [ #7 ] |
|
|
|
Elite Member |
Joined: 6-May-2007 Posts: 11348
From: Greensborough, Australia | | |
|
| @Jupp3
Quote:
From object point-of-view, the biggest differences I see between C and C++ are:
With f.ex. member functions, in C++ you do: obj->DoSomething(args);
instead of: obj->DoSomething(obj, args);
(In other words, "this" pointer is automatically silently passed in C++) |
Yes, at a basic level, there is that difference. Doing it the old way looks superfluous. The OOP way removes the redundancy of a repeating object, despite what is happenig behind the scenes.
The OS4 SDK at least provides a way to reduce the redundancy. Though it is embedded in an Interface, anyone can use the APICALL tag to OOP up an object function call to act like a method.
Like so:
struct Object { uint32 APICALL (*DoSomething)(struct Object *Self); }
uint32 DoSomething(struct Object *Self) { return 0: // Do Nothing Realy }
// Setup uint32 result; struct Object Object; struct Object *obj = &Object; obj->DoSomething = DoSomething;
// OOP it out result = obj->DoSomething(args);
Last edited by Hypex on 20-Feb-2019 at 04:20 PM.
|
|
Status: Offline |
|
|
matthey
| |
Re: BOOPSI and OOP Posted on 20-Feb-2019 21:08:35
| | [ #8 ] |
|
|
|
Elite Member |
Joined: 14-Mar-2007 Posts: 2393
From: Kansas | | |
|
| Quote:
Snorg wrote: Concerning performance and optimization, the programmer, being authoritative over the logic governing the domain of the application is, in principle, always in a better position to optimize than some pre-built delegate. Think global (e.g. link-time) optimization.
One inefficiency of modular programming resides in the isolation of algorithm contexts. If you have all of the source code for a build, the compiler can produce a more optimal binary. On the other hand, if everything exists in opaque units, the compiler has fewer opportunities to eliminate dead code, improve register allocation, reorganize loads and stores, etc.
In your code, you have to draw the line (many, many times). With the compiler, that line is blurred. Whether you think this is good or bad depends upon how well the compiler optimizes and how well you understand those optimizations.
So, by definition, there is a cost to incorporating static or shared binaries. But no reasonable person would suggest you don't use them. You make a decision, and sometimes that decision is made for you.
|
Yes, there are disadvantages to "modular" dynamic shared libraries.
1) limits cross-module optimization, especially function inlining opportunities 2) jump table overhead can be high for shallow functions 3) a library base pointer uses a register
Points #1 and #2 above can be partially addressed with hardware. Most code is optimized for performance instead of size which greatly increases the program size due to function inlining and loop unrolling. CPU design choices can spend more transistors to minimize these overheads which in turn reduce cache and memory requirements as function inlining and loop unrolling are minimized. There are existing CPUs where loop unrolling is slower (if not needed then it wastes cache) like the Intel "Sandy Bridge" i3, i5, i7 and even the 68060 in some cases. CPU designs should do more to encourage code sharing when optimizing for performance as this is likely more important to the cache efficiency and footprint than a good code density when optimizing for size.
Point #3 above is not as bad as it sounds. Statically linking all functions makes the program large and results in using more absolute addressing which gives bigger and slower code than relative addressing.
Shared libraries provided by the OS should be optimized sufficiently that using them mostly offsets the small performance overhead. This also encourages code sharing and reduces the footprint.
Quote:
Similarly, there is a cost to partitioning logic into discrete objects.
A great example is the standard C++ library: powerful, but that power comes at a sizable cost. For me, when performance matters, it is too large a cost. But I still have all the C++ language features to use as I see fit.
For example, with inlined template functions, I can write a function with parameterized (expression-based) constants, one which calls other such functions. What would otherwise become a (more) complex call graph in the binary becomes a single unit of (more) highly optimized code - but the source code remains (essentially) familiar to those who like C.
There is a dichotomy at work. Less is more, but more is more, too, when necessary.
If you use polymorphism, you will incur overhead. Still, sometimes it is the best option.
|
The C standard ISO/IEC committee has been reluctant to add some popular C++ features for various reasons. This probably has much to do with compiler complexity and changes necessary as resulting program performance or compiling performance. Despite keeping C simpler, it hasn't added many embedded features despite the persistent popularity in the embedded market. Without more C++ features on the desktop, it is likely to continue to lose users to C++ who have figured out how to minimize performance losses like you.
|
|
Status: Offline |
|
|
hth313
| |
Re: BOOPSI and OOP Posted on 20-Feb-2019 21:36:18
| | [ #9 ] |
|
|
|
Regular Member |
Joined: 29-May-2018 Posts: 159
From: Delta, Canada | | |
|
| Quote:
matthey wrote:
The C standard ISO/IEC committee has been reluctant to add some popular C++ features for various reasons. This probably has much to do with compiler complexity and changes necessary as resulting program performance or compiling performance. Despite keeping C simpler, it hasn't added many embedded features despite the persistent popularity in the embedded market. Without more C++ features on the desktop, it is likely to continue to lose users to C++ who have figured out how to minimize performance losses like you.
|
What popular features are you thinking of? |
|
Status: Offline |
|
|
Snorg
| |
Re: BOOPSI and OOP Posted on 21-Feb-2019 1:09:34
| | [ #10 ] |
|
|
|
Regular Member |
Joined: 1-Feb-2018 Posts: 117
From: Unknown | | |
|
| @matthey
Quote:
Most code is optimized for performance instead of size which greatly increases the program size due to function inlining and loop unrolling. CPU design choices can spend more transistors to minimize these overheads which in turn reduce cache and memory requirements as function inlining and loop unrolling are minimized ... CPU designs should do more to encourage code sharing when optimizing for performance as this is likely more important to the cache efficiency and footprint than a good code density when optimizing for size.
|
Absolutely! I have numerous code bases in which the builds favour size or speed depending upon architecture. My netbook always runs more compact code (loops less aggressively unrolled) faster precisely for the reasons you've stated. |
|
Status: Offline |
|
|
Jupp3
| |
Re: BOOPSI and OOP Posted on 21-Feb-2019 20:03:33
| | [ #11 ] |
|
|
|
Super Member |
Joined: 22-Feb-2007 Posts: 1225
From: Unknown | | |
|
| @Hypex
Quote:
Doing it the old way looks superfluous. The OOP way removes the redundancy of a repeating object, despite what is happenig behind the scenes. |
I don't quite agree with this "OOP way / other way" split, since both versions do exactly the same thing, with slightly different syntax.
And, of course in some (rare) cases, you don't even need the "this" pointer. Also, if it really bothers you that much, you can definitely seemingly get rid of it with some macros.
Personally, I usually end up doing something like this:
void ObjDoSomething(struct MyObj *obj) { // Do some common sanity checks, setups, whatever... if(obj->DoSomething) obj->DoSomething(obj); }
This allows you to do some common always needed setup / sanity checks in rather clean way, and as a bonus, might make dedicated member function obsolete for some objects, in which case it can be just a NULL pointer. |
|
Status: Offline |
|
|
matthey
| |
Re: BOOPSI and OOP Posted on 21-Feb-2019 20:11:44
| | [ #12 ] |
|
|
|
Elite Member |
Joined: 14-Mar-2007 Posts: 2393
From: Kansas | | |
|
| Quote:
hth313 wrote: What popular features are you thinking of?
|
C++ has shortcuts and helper functionality like smart pointers, auto types and lambda functions. Sometimes simple features can be really nice. For example, C99 adding features like // comments and intermixed declarations and statements made C feel like it wasn't in the stone ages anymore while improving compatibility with C++. Some of the heavy C++ features are likely popular too but best avoided. Embedded C++ tries to avoid these performance reducing and memory bloating features which include the following.
Exception handling Multiple inheritance mutable, a storage class specifier Namespaces Templates Run-time type information (typeid) Style casts (static_cast, dynamic_cast, reinterpret_cast and const_cast) Virtual base classes
The "Technical Report on C++ Performance" examines which C++ features cause performance loss.
http://www.open-std.org/jtc1/sc22/wg21/docs/TR18015.pdf
The following entry is found in the "Terms and definitions"
code bloat the generation of excessive amounts of code instructions, for instance, from unnecessary template instantiations.
|
|
Status: Offline |
|
|
bison
| |
Re: BOOPSI and OOP Posted on 21-Feb-2019 20:32:37
| | [ #13 ] |
|
|
|
Elite Member |
Joined: 18-Dec-2007 Posts: 2112
From: N-Space | | |
|
| @Jupp3
It should be relatively straightforward to create a source-to-source meta-language that translates
obj->DoSomething()
into
DoSomething(&obj)
which can then be compiled with a C compiler. I've done things like this using bison (as one might expect ).
_________________ "Unix is supposed to fix that." -- Jay Miner |
|
Status: Offline |
|
|
matthey
| |
Re: BOOPSI and OOP Posted on 21-Feb-2019 21:31:02
| | [ #14 ] |
|
|
|
Elite Member |
Joined: 14-Mar-2007 Posts: 2393
From: Kansas | | |
|
| Quote:
Snorg wrote: Absolutely! I have numerous code bases in which the builds favour size or speed depending upon architecture. My netbook always runs more compact code (loops less aggressively unrolled) faster precisely for the reasons you've stated.
|
Yes, lower performance hardware favors small code. Compilers usually only count best case (in L1 cache) instruction cycles without considering that their "code bloat" from excessive function inlining and loop unrolling may have pushed some of the code out of the cache. There is no equation for this and the behavior can be inconsistent and unpredictable. The "Technical Report on C++ Performance" measured some of the C++ inlining and sometimes it did *not* give a performance benefit. Unfortunately, code bloat is the lesser of 2 evils without hardware which reduces the advantage of function inlining and loop unrolling to a minimum. There is an applicable and well written paragraph in the Technical Report which follows.
"An old rule of thumb is that there is a trade-off between program size and execution speed – that techniques such as declaring code inline can make the program larger but faster. But now that processors make extensive use of on-board cache and instruction pipelines, the smallest code is often the fastest as well. Compilers are free to ignore inline directives and to make their own decisions about which functions to inline, but adding the hint is often useful as a portable performance enhancement. With small one or two-line functions, where the implementation code generates fewer instructions than a function preamble, the resulting code may well be both smaller and faster."
It is true that inlining small functions is predictably "both smaller and faster" but compilers are choosing the lesser of 2 evils with massive amounts of inlining expecting that ever growing CPU cache sizes will take care of the code bloat. The result is that C++ is becoming a language for high performance hardware, especially when using code bloating features like templates.
|
|
Status: Offline |
|
|
Mr_Capehill
| |
Re: BOOPSI and OOP Posted on 22-Feb-2019 16:14:33
| | [ #15 ] |
|
|
|
Super Member |
Joined: 15-Mar-2003 Posts: 1933
From: Yharnam | | |
|
| @matthey
How namespaces reduce performance? |
|
Status: Offline |
|
|
matthey
| |
Re: BOOPSI and OOP Posted on 22-Feb-2019 17:59:19
| | [ #16 ] |
|
|
|
Elite Member |
Joined: 14-Mar-2007 Posts: 2393
From: Kansas | | |
|
| Quote:
Mr_Capehill wrote: How namespaces reduce performance?
|
If you read the "Technical Report on C++ Performance" linked above, it says the following.
"Namespaces do not add any significant space or time overheads to code. They do, however, add some complexity to the rules for name lookup. The principal advantage of namespaces is that they provide a mechanism for partitioning names in large projects in order to avoid name clashes."
...
"With all names, longer names take up more space in the program’s symbol table and may add a negligible amount of time to dynamic linking. However, there are tools which will strip the symbol table from the program image and reduce this impact."
The only impact to programs using namespaces is longer load times when the executable is not stripped. Compile times and compile memory use may increase. Perhaps Embedded C++ has the goal of keeping compiler overhead low enough to compile on lower performance hardware and maybe even some embedded hardware. It has not been too popular perhaps because it cuts debatable features like this. There are other standards which restrict C++ features but add more. Apple chose to restrict less for the libkern C++ runtime.
"When they designed the OS X kernel, Apple engineers decided upon a restricted form of C++ because they felt the excluded features—exceptions, multiple inheritance, templates, and runtime type information (RTTI)—were either insufficient or not efficient enough for a high-performance, multithreaded kernel."
https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/WritingDeviceDriver/CPluPlusRuntime/CPlusPlusRuntime.html#//apple_ref/doc/uid/TP30000695-BAJIBFDE
Dr. Volker Barthelmann was looking into adding Embedded C++ support to the vbcc compiler. He has a background in the automotive embedded industry and vbcc is targeted at embedded use even though it seems to be more popular for retro use.
|
|
Status: Offline |
|
|
Hypex
| |
Re: BOOPSI and OOP Posted on 23-Feb-2019 13:57:08
| | [ #17 ] |
|
|
|
Elite Member |
Joined: 6-May-2007 Posts: 11348
From: Greensborough, Australia | | |
|
| @Jupp3
Quote:
I don't quite agree with this "OOP way / other way" split, since both versions do exactly the same thing, with slightly different syntax. |
In this simple case they would. Though the OOP way is designed to be object centric.
Quote:
And, of course in some (rare) cases, you don't even need the "this" pointer. Also, if it really bothers you that much, you can definitely seemingly get rid of it with some macros. |
In some cases the pointer wouldn't be needed but it does contain all the variables relative to that object.
Possibly some macros could work but it would restrict the function names somewhat. And since OS4 C allows methods to be embedded in C structures it would make sense to use them.
Quote:
This allows you to do some common always needed setup / sanity checks in rather clean way, and as a bonus, might make dedicated member function obsolete for some objects, in which case it can be just a NULL pointer. |
It does. Though you always need to prepend the method name with the Object and have a function ready for that object.
At this point I thnk of AmigaE. AmigaE has the unique ability of being a procedural language with OOP features. You could program in it without using OOP at all. But when you use OOP it somehow can mix the traditional procedural style with OOP at ease. You can seamlessly program AmigaOS while also using OOP in the program structure. Languages like C/++ could learn from this.
Unfortunately I don't see evidence of any OOP based Amiga APIs being ported to E fuily and making use if it's features. Be that BOOPSI or MUI.
I've seen MUI code in E and it looks shocking. Total mess. Given that E can do OOP it is an abomination. Now MUI isn't exactly suited to pure C either because of its nature. But since E is considered second best to E a basic conversion was all that was done. A proper E port of the MUI API includes would make use of the OOP features and be a superior language to code it on.Last edited by Hypex on 23-Feb-2019 at 01:59 PM.
|
|
Status: Offline |
|
|
Jupp3
| |
Re: BOOPSI and OOP Posted on 23-Feb-2019 14:36:08
| | [ #18 ] |
|
|
|
Super Member |
Joined: 22-Feb-2007 Posts: 1225
From: Unknown | | |
|
| @Hypex
Quote:
At this point I thnk of AmigaE. AmigaE has the unique ability of being a procedural language with OOP features. You could program in it without using OOP at all. |
Like C++?
And yes, I prefer it when languages give some freedom to the user. If a language tries to restrict itself to be "OOP-only", a clever coder can work his way around that.
Quote:
I've seen MUI code in E and it looks shocking. Total mess. Given that E can do OOP it is an abomination. |
Also, I have seen OOP code, that's total mess, and would be WAY less so, if done in the traditional procedural way.
It just seems that some people get overly obsessed over OOP, and want to enforce it on even the smallest details.
At worst, you have code do some really minor things, but still, you have to read through layers upon layers of code in different files, to have even vague idea of what it actually does. |
|
Status: Offline |
|
|
bison
| |
Re: BOOPSI and OOP Posted on 23-Feb-2019 19:03:13
| | [ #19 ] |
|
|
|
Elite Member |
Joined: 18-Dec-2007 Posts: 2112
From: N-Space | | |
|
| @Jupp3
Quote:
At worst, you have code do some really minor things, but still, you have to read through layers upon layers of code in different files, to have even vague idea of what it actually does. |
I've refactored OO code and found this to be true -- everything is so tightly coupled that everything has be be changed before the first recompile. There's no "sneaking up on it' a small step at a time.
_________________ "Unix is supposed to fix that." -- Jay Miner |
|
Status: Offline |
|
|
Snorg
| |
Re: BOOPSI and OOP Posted on 24-Feb-2019 7:09:55
| | [ #20 ] |
|
|
|
Regular Member |
Joined: 1-Feb-2018 Posts: 117
From: Unknown | | |
|
| @bison
Encapsulation and abstraction are intended to de-couple software modules - that is, to reduce dependencies between different functions and methods. What tends to happen is that programmers take shortcuts rather than respecting object boundaries - i.e. they break encapsulation.
void f (A& a) { a.b().c.d(); // if a, b, c, or d change, this is likely broken }
Something they don't (or didn't) teach: don't focus on class frameworks / hierarchies, think in terms of object hierarchies. Events go up, not down or sideways. Directives go down, not up or sideways. Better encapsulation implies a shallower graph of *dependent* parents and descendants. You don't need to know the particulars of a parent when firing an event, and it is better to issue directives only to children rather than making assumptions about the organization and composition of descendants in the object tree.
By compartmentalizing communication in this way, you can largely prevent the tight coupling problem.
|
|
Status: Offline |
|
|