R6 icon indicating copy to clipboard operation
R6 copied to clipboard

Soft-locked objects?

Open jchrom opened this issue 3 years ago • 4 comments

I would like a controlled way to add methods/fields to instantiated objects. For example, have a class producing locked objects which cannot be extended except for a qualified decorator. A finite set of decorators for a given set of classes would restrict users in how they can modify objects.

A brute force solution might be to let the decorator call rlang::env_unlock(), decorate, then call lockEnvironment() to reinstate the lock.

But it does not seem very clean (although I don't know what specific problems it could cause). Another option might be to implement the locking by adding some attributes to object environments and overload the $.

I wonder what your thoughts are on this "extending objects, but only by a dedicated function" idea. And if you can think of any interesting problems which may arise as a result of releasing the lock after instantiation.

jchrom avatar Mar 25 '21 16:03 jchrom

As you've noticed, base R has a function for locking environments, but it doesn't have a function for unlocking environments. One of the primary goals for R6 is to have no dependencies other than base R. (Hypothetically, if there was a big enough advantage to taking a dependency on a package, I'd consider it, but I don't think this situation alone makes it worthwhile.)

That said, there's nothing stopping you from implementing this in your own code. You could have a function that unlocks, modifies, and then locks again.

I'm against adding $.R6 and $<-.R6, because there is a nontrivial performance penalty for doing so. But again, you could implement your own $ and $<- methods for your own classes that do whatever you want.

wch avatar Mar 25 '21 17:03 wch

Thanks for looking into it! Yeah this "real" unlocking can be done easily without rlang, e.g. by just using the C API like the pkgload did before it added the rlang dependency. So that's not a big obstacle, safe for the fact that it would mean using non-public API.

I wanted to see if you would object to this approach in principle. If my code unlocked object environments locked by R6, does that seem like a potentially bad idea to you?

jchrom avatar Mar 25 '21 18:03 jchrom

It's always possible in principle that the R source code will change the locking implementation so that different bits are used, or there's a different data structure altogether. If happens, your code would probably do something bad to the data structures, and probably lead to crashing or memory corruption. In practice, this seems very unlikely to me, but I still wouldn't do it for production code. For development-time stuff like pkgload and rlang's env_unlock function, it's probably OK.

wch avatar Mar 25 '21 19:03 wch

Another idea: I could shallow-clone the object without locking the new envs (via a modified clone method). The decorator would add new bindings to the clone, which would be locked afterwards if the original was locked. The original is then dropped.

This could avoid the need for s3 dispatch or non-public API. Sounds a bit too simple to be true though.

jchrom avatar Mar 26 '21 06:03 jchrom