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

What exactly set(obj, f, val) means? #157

Open
aplavin opened this issue Jul 18, 2024 · 3 comments
Open

What exactly set(obj, f, val) means? #157

aplavin opened this issue Jul 18, 2024 · 3 comments

Comments

@aplavin
Copy link
Member

aplavin commented Jul 18, 2024

The question may sound strange, but what exactly y = set(x, f, val) means/supposed to mean?
The contract specifies that f(y) == val, but what about other parts of the object?
Consider this hypothetical scenario:

struct Ellipse1
    major_axis
    minor_axis
end

struct Ellipse2
    major_axis
    minor_major_ratio
end

major_axis(e::Ellipse1) = e.major_axis
major_axis(e::Ellipse2) = e.major_axis

minor_axis(e::Ellipse1) = e.minor_axis
minor_axis(e::Ellipse2) = e.major_axis * e.minor_major_ratio

minor_major_ratio(e::Ellipse1) = e.minor_axis / e.major_axis
minor_major_ratio(e::Ellipse2) = e.minor_major_ratio

What should set(ellipse, minor_axis, val) do: keep the ratio or the major axis constant?
Same question for set(ellipse, minor_major_ratio, val): does it keep major axis? Minor? Average?..

Should it be the same or different for Ellipse1 vs 2? If one implements set() based on the implementation (internal fields) of these objects, it will result in a weirdly different set() behavior for two ellipse types that are otherwise treated equivalently.

@jw3126
Copy link
Member

jw3126 commented Jul 18, 2024

I expect from y = set(x, f, val) that it satisfies the lens laws, unless f is some exotic optic. But for a function, I definitely expect the lens laws.

In some cases like f = @o _.major_axis there is a unique natural product decomposition of the object and then I expect
that decomposition to be respected.

In other cases like your examples, there is no unique natural decomposition. In these cases, it is best to make clear what is happening, by documentation, comments, more explicit names.

In your example, I would have no expectation of what minor_major_ratio does exactly. For minor_axis I would expect that it respects the major_axis.
But it is a bit subjective to consider ellipse = minor_axis x major_axis more natural than ellipse = major_axis x minor_major_ratio.

@aplavin
Copy link
Member Author

aplavin commented Jul 18, 2024

I expect from y = set(x, f, val) that it satisfies the lens laws

Yeah, that part is clear – but I don't think lens laws specify what happens to the part of x "orthogonal" to f.

In some cases like f = @o _.major_axis there is a unique natural product decomposition of the object

With fields/properties/collection indices there's this natural decomposition, true. I think Accessors do a good job at preserving it!

Maybe, the only right answer here is that one needs to think carefully when defining function setters, to ensure there's a natural "orthogonal" decomposition. I found myself with a more involved case of this "ellipse example", where I defined several setters to do whatever appeared natural at different times, and found out they aren't quite consistent.

Unfortunately, doesn't seem like there is a way to programmatically test this kind of properties, they are hard to even define in text. Do you happen to know of solutions in "stricter" languages like Haskell/Scala/... ?

@jw3126
Copy link
Member

jw3126 commented Jul 18, 2024

I don't know about other languages. One approach to make the decomposition used obvious would be something like:

@set Ellipse2(ellipse).minor_major_ratio = ...
@set Ellipse1(ellipse).minor_radius = ...

More mathematically this makes explicit the isomorphism used between typeof(ellipse) and a type for which the decomposition is obvious.

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

No branches or pull requests

2 participants