Open guslipkin opened 2 months ago
I think you could do this by having a setter that throws an error if the Date is already set (not NULL
). There's also been the suggestion of a property with a dynamic default, see #376.
That's a good idea, but I can't quite get it to work because there are some barriers in the way, including the issue I mentioned in #405 where you can't use default values and a constructor in tandem.
@birthdate
without any checks, it cannot be NULL
because the birthdate
property has a class S7::class_Date
. I would need to create a union with S7::class_any
because NULL
does not have a class.default = NULL
then call person('Unixtime')
, I get an error that there is no default value because the default
argument defaults to NULL
, so that requires a switch to NA
default
argument.Our setup now looks like this:
person <- S7::new_class(
name = 'person',
properties = list(
'name' = S7::class_character,
'birthdate' = S7::new_property(
class = S7::class_Date,
getter = \(self) { self@birthdate },
setter = \(self, value) {
if (is.na(self@birthdate)) self@birthdate <- value else warning('Cannot set read-only value')
return(self)
},
),
'age' = S7::new_property(
class = S7::class_any,
getter = \(self) { Sys.Date() - self@birthdate }
)
),
constructor = \(name, birthdate = as.Date(NA)) {
S7::new_object(
S7::S7_object(),
'name' = name,
'birthdate' = birthdate
)
}
)
person('Unixtime')
If you run this, you'll get a C stack error. I'm not really sure why this is.
Currently the documentation suggests that read-only properties (those with only a getter and no setter) are for computed values such as
now
or calculating using other properties of the object. However, sometimes you want to create an object with a value that doesn't change, isn't allowed to change, and isn't calculated from other values.Take this person class, for example. We want to allow the birthdate to be set once and only once on construction, but the person's age will be calculated using the current date.