Yes, indeed some programming language provides more strict ways of denying modification to internal data structures details than others. But given my background pre-elixir (PHP) I can assert it is possible to "live" with that type of flexibility, although it requires more vigilance.
On the "information hiding" bit, I was actually referring to: *"In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change).Written another way, information hiding is the ability to prevent certain aspects of a class or software component from being accessible to its clients, using either programming language features (like private variables) or an explicit exporting policy." *( https://en.wikipedia.org/wiki/Information_hiding) Hope this clarifies my POW. Anyway, I'm happy to see you agree, on a certain degree, that having some ways of making structs more "protected" is something Elixir should address. Happy to help or join any further discussion on this if it can help. On Fri, 31 May 2019 at 15:28, José Valim <[email protected]> wrote: > > I don't think this is a problem. That is what in OOP I would call a > "dirty public setter", which can obviously be used, but it should not. > Monitoring against these kind of bad practices is easier anyway. > > Except that most OOP languages allow you to forbid this altogether for > certain fields while it is quite hard to provide the same guarantee here. > > > Also, having "private" structs will give Elixir community a big message > such as: "we care about information hiding". > > Just to clarify, I think "information hiding" is the wrong end-goal here. > We actually want to *avoid* hiding state (information) because trying to > make sense of a system where you have a bunch of small state hidden > everywhere is quite hard. A better word would be "we care about defining > proper boundaries". > > *José Valim* > www.plataformatec.com.br > Skype: jv.ptec > Founder and Director of R&D > > > On Fri, May 31, 2019 at 3:36 PM Francesco Lo Franco < > [email protected]> wrote: > >> Hi Josè, thanks for your reply. >> >> Sorry I have done a poor job explaining myself. What I meant I'd love to >> have is: >> >> - avoiding "public" write/read direct access to fields in a struct >> - forcing users to use an API to "construct" a new struct >> >> I'm pretty sure with these changes achieving the goal "valid struct at >> 'all' times" would be much easier. >> >> >> I understand enforcing types for struct fields would be pretty complex. >> Besides, this could be worked around wrapping even simple fields (binaries >> or integers) into structs (someone said value objects?). >> >> >> Referring to your example: >> >> def bad(user) do >> >> %{user | name: 5} >> >> end >> >> >> I don't think this is a problem. That is what in OOP I would call a >> "dirty public setter", which can obviously be used, but it should not. >> Monitoring against these kind of bad practices is easier anyway. >> >> Also, having "private" structs will give Elixir community a big message >> such as: "we care about information hiding". >> >> >> >> On Wednesday, 4 October 2017 10:08:17 UTC+1, Maciej Kaszubowski wrote: >>> >>> Hello, >>> >>> *Proposed feature* >>> >>> I'd like to propose another improvement on structs. Inspired by >>> @enforce_keys, >>> I'd like to propose adding @guards which can help to validate the types >>> of the fields in the struct. >>> >>> Example usage: >>> >>> defmodule MyStruct do >>> @guards [name: :is_binary] >>> defstruct [:name] >>> end >>> >>> >>> which will fail if the given condition is not satisfied: >>> >>> iex(2)> %MyStruct{name: 5} >>> ** (ArgumentError) The following fields didn't match the guards: struct >>> MyStruct: [{:name, :is_binary, 5}] >>> expanding struct: MyStruct.__struct__/1 >>> >>> >>> *Notes* >>> >>> - As the example shows, the behaviour will be similar to >>> @enforce_keys - it will be checked only when creating the struct, not >>> when >>> updating >>> - Using module attribute allows to keep this optional and allows to >>> keep backwards compatibility >>> >>> *Possible implementation* >>> >>> With https://hexdocs.pm/elixir/master/guards.html and Kernel.apply/3, we >>> can modify existing def __struct__(kv) from Kernel: >>> >>> >>> def __struct__(kv) do >>> {map, errors} = >>> Enum.reduce(kv, {@struct, {[], @enforce_keys}}, fn {key, val}, {map, >>> {type_errors, key_errors}} -> >>> >>> guard = @guards[key] >>> if guard && apply(Kernel, guard, [val]) do >>> {Map.replace!(map, key, val), {type_errors, >>> List.delete(key_errors, key)}} >>> else >>> { >>> Map.replace!(map, key, val), >>> {[{key, guard, val} | type_errors], List.delete(key_errors, >>> key)} >>> } >>> end >>> >>> end) >>> case errors do >>> {[], []} -> map >>> {types, []} -> >>> raise ArgumentError, "The following fields didn't match the >>> guards: " <> >>> "struct #{inspect __MODULE__}: #{inspect types}" >>> end >>> end >>> >>> >>> >>> This, of course, needs style improvements (and validation of required >>> fields which is currently removed for the sake of clarity), but this is >>> only a proof of concept to verify that the implementation is possible and >>> quite easy. >>> >>> *Why not use @type?* >>> >>> While it would be cool to be able to verify the types based on >>> typespecs, it would be harder because I think not all types can be easily >>> validated. The suggested approach with guards will be feel more familiar >>> because we can already do this for functions. Adding guard validation for >>> struct fields feels like reasonable step. >>> >>> *What do you think?* >>> >>> I'd be happy to start working on this feature, but I wanted to know what >>> do you all think about this. >>> >>> >>> Cheers, >>> Maciej >>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/ad8102ee-0faa-4576-a1e2-5de1fb211ee7%40googlegroups.com >> <https://groups.google.com/d/msgid/elixir-lang-core/ad8102ee-0faa-4576-a1e2-5de1fb211ee7%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> For more options, visit https://groups.google.com/d/optout. >> > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Jr_4dSSWz9kuEt9xMiovPwjJ_FByProtXRuNJhRhmgCw%40mail.gmail.com > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Jr_4dSSWz9kuEt9xMiovPwjJ_FByProtXRuNJhRhmgCw%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CACdimjnszCDNeQf7r5XDm6taMH9k1q%2B5z040ALHMrKmYXoHjJw%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
