On Thu, May 21, 2015 at 3:44 AM, Nick Wellnhofer <[email protected]> wrote:
> There's also the issue of keeping the ABI compatible if the "final" property
> of a method is removed, and the method implementation is subsequently
> removed or overridden in a subclass. Such a change is backward compatible,
> so it should be supported in line with our strong ABI compatibility
> guarantees.
>
> To make this work, we must only use direct function calls for final methods
> implemented in a "source" parcel, not in an "included" parcel.
> Unfortunately, this change mostly defeats the performance effects of making
> core Clownfish classes like String, Vector, or Hash final. For example, a
> parcel like Lucy couldn't use a direct function call for things like Vec_Add
> anymore.
Okeedoke -- I'll rework the pull request to further limit the optimization.
Without JIT compilation or even link-time-optimization, we're not going to see
any kind of big speedup, anyhow. If we could inline the code or at least
resolve to a fixed address, things might be different. But with standard
linking, we're looking at a PLT lookup, which isn't that different from a
vtable lookup. Both involve multiple levels of indirection. Both will cause
a control hazard.
Making explicit choices about what classes and methods are final and what may
be overridden is more about good design. "Design and document for
inheritance or else prohibit it." -- Joshua Bloch
> There's always the option to convert a method like Vec_Add into an "inert"
> function Vec_add (like we did for some Obj methods).
I don't think any inert functions should be made available as instance
methods, though. We can't stop it from happening with Perl, but it's not
something we should strive to support across all hosts.
> But we don't
> autogenerate bindings for inert functions. It would be nice if it was
> possible to generate bindings for certain inert functions that take an
> object of their class ("self") as first argument.
For some hosts, we could autogenerate bindings for inert functions regardless
of signature, so long as all types can be mapped unambiguously. Python, Perl
and Ruby are all pretty straightforward:
// Clownfish header for `public class Foo` in parcel "example"
public inert int32_t
add(int32_t a, int32_t b);
# Perl: ordinary sub -- i.e. not a class method.
use Example::Foo qw( add );
my $result = add(1, 2);
# Python: probably @staticmethod, possibly @classmethod.
from example import Foo
result = Foo.add(1, 2)
# Ruby: class method
require "example"
result = Foo.add(1, 2)
With Go, though, we run into a namespacing problem. Clownfish parcels can
have inert functions with the same name in multiple classes. In Go, they all
end up in the same Go package and will clash.
// Go: ordinary func (not method)
result := example.Add(1, 2)
> On the other hand, we could simply postulate that a final method must never
> be made non-final.
I hadn't thought hard about this use case before. Adding `final` to a method
breaks compat because there could be a subclass out there overriding it. I
suppose that removing `final` need only break compat if the compiler performs
optimizations in other parcels. I'm fine with foregoing those optimizations
and making the removal of `final` officially supported.
Marvin Humphrey