I'd say that if you want to hardcode that behavior, you'd better not use object-oriented programming. Simply implement it as functions calling other functions.
("that behavior" as understood by me: if calling foo2
from inside the code that has been called as super#foo1
, then exactly the foo2
from the implementation of the superclass should be called, not from the more "specific" implementations from subclasses)
It's the simplest and cleanest and clearest way to proceed: program functions that do what you want.
Or you should explain to yourself and to us: Why do you need OOP? The reason for it is not given in the question text. Why make foo1
and foo2
methods rather than independent functions? (Aside from foo1
and foo2
, you may have some objects and classes and methods in your program, where appropriate).
Wondering whether this question comes from comparison to other lnaguages
If you know another OO language, that's strange that you want "that behavior" from OOP: it's not the behavior expected in, say, Java or C++, because they employ the concept of a table of virtual methods that is associated with each object at run-time, so when calling a method in your program, it gets dispatched at run-time to the implementation of that method actually associated with the object. So, in short: whenever you use a method-calling expression in your program, you commit yourself to this principle of finding the implementation of the method ("late binding"), as pointed out by gasche. Although still cf. the differences between OCaml and languages implemented with a virtual methods table pointed out by Niki Yoshiuchi.
Formalizing all the discussion of the available and wanted behaviors
Although what you want might not be the expected and available behavior in many popular OO languages, it is imaginable and could be implementable in some specific OOP systems, if one has access to the OOP implementation internals.
Say, if in some implementation, super
is a structure holding the methods table of the superclass (to fallback to when resolving a method call for the current object), and the methods are functions which must receive the object (the methods table) as the 1st arg, then to perform what you want, one would write super.foo1(super, y)
.
(I actually wonder whether there are OOP implementations whose internals are exposed to the programmer and that allow doing such a call.)
Whereas the usual OOP behavior would be expressed in this system by this.foo1(this, y)
(where this
is the methods table for the current object.)
Your OCaml call super#foo1 y
or a Java super.foo1(y);
translates into this "my" system as super.foo1(this, y)
. (Although still cf. the differences pointed out by Niki Yoshiuchi between OCaml and languages like Java implemented with a virtual methods table.)
You see the differences between the 3 cases.
Appendix. Looking for languages that would work that way
Hmm, PHP could be a language where that behavior would be possible, but:
- only on "class-level" programming (static methods), not object-level;
- only when you hardcode some strange "late static binding" at the function calls:
#!/usr/bin/php
<?php
class Foo {
public static function foo1($y) {
echo "foo1\n";
static::foo2($y-1);
}
public static function foo2($y) {
echo "foo2\n";
if ($y > 0)
static::foo2($y);
else
echo "end\n";
}
}
class Bar extends Foo {
public static function foo2($y) {
echo "bar2\n";
if ($y > 0)
Foo::foo1($y);
else
echo "endbar\n";
}
}
class Model extends Foo {
public static function foo2($y) {
echo "model2\n";
if ($y > 0)
static::foo1($y);
else
echo "endmodel\n";
}
}
Model::foo2(3);
Bar::foo2(3);
?>
The Model behaves in a sense like standard OO objects with virtual methods, and Bar as you wanted:
$ ./test-force-super-binding.php | head -20
model2
foo1
model2
foo1
model2
foo1
model2
endmodel
bar2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$
(BTW, using parent::
instead of Foo::
wouldn't get us at your wanted behavior.)
I don't understand the prupose of the insane PHP's binding specifications like static::
, which are of some effect only for static methods (i.e., class-level programming).
An analoguous C++ example doesn't give an OO object-level behavior by default:
#include<iostream>
class Foo {
protected:
static void foo1(int y) {
std::cout << "foo1" << std::endl;
foo2(y-1);
}
public:
static void foo2(int y) {
std::cout << "foo2" << std::endl;
if (y > 0)
foo2(y);
else
std::cout << "end" << std::endl;
}
};
class Bar: public Foo {
public:
static void foo2(int y) {
std::cout << "bar2" << std::endl;
if (y > 0)
foo1(y);
else
std::cout << "endbar" << std::endl;
}
};
int main() {
Bar::foo2(3);
return 0;
}
-- it gives your wanted behavior:
$ ./a.out | head -10
bar2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$
even without any special qualifier at the function call in the code for Bar::foo2()
, so not interesting for us.
What about Java's static methods?.. (Do they differ from C++ and give us a virtual-method-like resolution of the function-calls by default?)