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

Immutability #24

Open
maxim opened this issue Sep 27, 2018 · 4 comments
Open

Immutability #24

maxim opened this issue Sep 27, 2018 · 4 comments

Comments

@maxim
Copy link

maxim commented Sep 27, 2018

Great lib, love how small and efficient it is. Would be great if it could produce immutable objects, either frozen by default, or with skipped attribute writers. Curious to hear your thoughts.

@davydovanton
Copy link
Owner

hey, thanks for feedback!
About immutability. I think it's a good idea. I think we can use something like this:

class User
  include ShallowAttributes

  attribute :name, String
  attribute :age, Integer
  attribute :birthday, DateTime
end

user = User.new
user.name = 'Anton' # => okay

class ImmutableUser
  include ImmutableShallowAttributes

  attribute :name, String
  attribute :age, Integer
  attribute :birthday, DateTime
end

user = ImmutableUser.new
user.name = 'Anton' # => raise error

WDYT?

@maxim
Copy link
Author

maxim commented Sep 29, 2018

Sounds like a good option. What do you think about per-attribute?

attribute :name, String, writer: false # true/false/:protected

And for any such non-true attribute, it would also be excluded from mass assignment via attributes=.

@davydovanton
Copy link
Owner

so, I think it can be hard for implementing. Also, usually you need to use full immutable object raise than immutable attribute (only my experience) 🤔

@maxim
Copy link
Author

maxim commented Sep 29, 2018

Definitely agree that usually you want full-immutable. I've seen the exception recently where sometimes you have a persistable object and you want to assign id field only after persistence. OTOH, this can also be done by dup-ing it.

Whether it's per-attribute, or full-immutable, your code is really well designed to accommodate it. I was able to get like 80% there by simply overwriting initialize_setter in a subclass with

def initialize_setter(name, *)
  super.tap { private name } 
end

This achieved the effect that you couldn't call a setter from outside, but initialize still worked. However, mutation was still possible via attributes=. I didn't find an easy way to patch that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants