RConsortium / S7

S7: a new OO system for R
https://rconsortium.github.io/S7
Other
387 stars 33 forks source link

External S7 classes #341

Open hadley opened 1 year ago

hadley commented 1 year ago

Prior to this PR, if class A in package A extends class B in package B, class A will include a copy of the definition of class B at build-time. Methods are not also copied, so if class B is later updated and package B reinstalled, it's possible to end up with in an inconsistent state where you have the class definition from version 1 and the methods from version 2.

This PR adds a new "external class" object designed to ameliorate this problem by doing more work at run-time rather at build-time. For example, the constructor of class B will now have arguments ... and it will figure out which arguments go to which constructor at run-time (we prefer to do this at build time in order to generate a constructor with named arguments that can be auto-completed etc).

Fixes #317

hadley commented 1 year ago

Since I've now realised that #250 admits a much simpler solution, I think this should take on more of a shape of new_external_generic(), with an explicit package argument. I think this will still need to switch to a dynamic constructor (i.e. take ... and do argument dispatch at run time) but hopefully that won't require too much refactoring of the existing code to determine which arguments go where.

And then we can automatically use that when parent has a package that isn't equal to the current package, so there's little user intervention required (except if you want to extend a class in a suggested package, which is likely to be relatively rare).

hadley commented 1 year ago

To do:

hadley commented 12 months ago

@DavisVaughan @t-kalinowski this will need discussion with the full committee before we merge it, but I'd love to get your initial thoughts on both the overall idea and the implementation.

lawremi commented 1 month ago

An alternative approach would be to record in the namespace every parent class passed to new_class() that is from another package. At namespace load, we simply check whether all of the cached classes are the same (by whatever definition we want) as those currently defined in their original package. If the check fails, we ask the user to reinstall the package. It's the safest approach, because it might be that the package needs to be updated anyway.

This is similar to how some C programs check for ABI breakage by comparing struct sizes with those compiled into a library.