Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot override field with method in subclass #166

Open
hriebl opened this issue Nov 5, 2018 · 8 comments
Open

Cannot override field with method in subclass #166

hriebl opened this issue Nov 5, 2018 · 8 comments
Labels
feature a feature request or enhancement

Comments

@hriebl
Copy link

hriebl commented Nov 5, 2018

I just figured out that it's not possible to override a field with a method in a subclass. Paradoxically, the opposite direction works. Maybe this is the desired behavior or I overlooked this aspect in the package documentation/the other GitHub issues. If so, please let me know.

field → field works:

parent <- R6Class("parent", list(
  x = 1
))

child <- R6Class("child", inherit = parent, list(
  x = 2
))

parent$new()
# <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: 1
child$new()
# <child>
#   Inherits from: <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: 2

field → method doesn't work:

parent <- R6Class("parent", list(
  x = 1
))

child <- R6Class("child", inherit = parent, list(
  x = function() 2
))

parent$new()
# <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: 1
child$new()
# <child>
#   Inherits from: <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: 1

method → method works:

parent <- R6Class("parent", list(
  x = function() 1
))

child <- R6Class("child", inherit = parent, list(
  x = function() 2
))

parent$new()
# <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: function ()
child$new()
# <child>
#   Inherits from: <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: function ()

parent$new()$x()
# [1] 1
child$new()$x()
# [1] 2

method → field works:

parent <- R6Class("parent", list(
  x = function() 1
))

child <- R6Class("child", inherit = parent, list(
  x = 2
))

parent$new()
# <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: function ()
child$new()
# <child>
#   Inherits from: <parent>
#   Public:
#     clone: function (deep = FALSE)
#     x: 2

parent$new()$x()
# [1] 1
@wch
Copy link
Member

wch commented Nov 5, 2018

This is a bug. I think that it makes sense to disallow overriding in either direction, from method->field or field->method, because then the subclass will behave differently from the superclass.

@hriebl
Copy link
Author

hriebl commented Nov 6, 2018

Actually, I was a bit surprised it didn't work, because there is usually no type checking in R. I was trying to write a "template class" with a lot of NA fields, which the subclasses would override with useful methods. But probably you're right and it would be more sane to prohibit this behavior altogether.

@wch
Copy link
Member

wch commented Nov 6, 2018

I was wondering about the use case you had in mind. We've been thinking about interfaces for R6, but haven't yet decided on a course of action (#163).

@hriebl
Copy link
Author

hriebl commented Nov 6, 2018

Interfaces seem like the proper way to implement what I was trying to achieve. Anyway, I think it would be a good idea to make the "field → method", "method → field" behavior consistent. :)

@jayqi
Copy link

jayqi commented Nov 11, 2018

I was trying to write a "template class" with a lot of NA fields, which the subclasses would override with useful methods. But probably you're right and it would be more sane to prohibit this behavior altogether.

@hriebl A different idea that works today is to define methods that don't do anything in your template class, or to be a little fancier, define methods that error out if called.

@hriebl
Copy link
Author

hriebl commented Nov 19, 2018

Thank you, @jayqi, I ended up doing something like that. The whole bug is not a big deal, you can definitely work around it, but it's a bit weird...

@hadley hadley added the feature a feature request or enhancement label Apr 3, 2020
@krlmlr
Copy link
Member

krlmlr commented Dec 11, 2020

Is this related to the inability to access public fields via super$?

library(R6)

MySuper <- R6Class(
  "MySuper",
  public = list(
    public_member = NULL,
    initialize = function(...) {
      self$public_member <- 1
    },
    get_super_public_member = function() {
      self$public_member
    }
  )
)

MySub <- R6Class(
  "MySub",
  inherit = MySuper,
  public = list(
    get_public_member = function() {
      list(
        self = self$public_member,
        super = super$public_member
      )
    }
  )
)

my_sub <- MySub$new()
my_sub$get_super_public_member()
#> [1] 1
my_sub$get_public_member()
#> $self
#> [1] 1
#> 
#> $super
#> NULL

Created on 2020-12-11 by the reprex package (v0.3.0)

@MSHelm
Copy link

MSHelm commented Sep 28, 2021

I also just stumbled over this issue. I initially had defined the method as a field = NULL in the super class and defined the according method in the subclass. Would be great if this behavior could be made consistent or described in the documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature a feature request or enhancement
Projects
None yet
Development

No branches or pull requests

6 participants