{"action":"created","issue":{"url":"https://api.github.com/repos/JOML-CI/JOML/issues/52","labels_url":"https://api.github.com/repos/JOML-CI/JOML/issues/52/labels{/name}","comments_url":"https://api.github.com/repos/JOML-CI/JOML/issues/52/comments","events_url":"https://api.github.com/repos/JOML-CI/JOML/issues/52/events","html_url":"https://github.com/JOML-CI/JOML/issues/52","id":103238798,"number":52,"title":"Using JOML types as constants/immutability","user":{"login":"immortius","id":1388872,"avatar_url":"https://avatars.githubusercontent.com/u/1388872?v=3","gravatar_id":"","url":"https://api.github.com/users/immortius","html_url":"https://github.com/immortius","followers_url":"https://api.github.com/users/immortius/followers","following_url":"https://api.github.com/users/immortius/following{/other_user}","gists_url":"https://api.github.com/users/immortius/gists{/gist_id}","starred_url":"https://api.github.com/users/immortius/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/immortius/subscriptions","organizations_url":"https://api.github.com/users/immortius/orgs","repos_url":"https://api.github.com/users/immortius/repos","events_url":"https://api.github.com/users/immortius/events{/privacy}","received_events_url":"https://api.github.com/users/immortius/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-08-26T11:01:41Z","updated_at":"2015-08-30T14:04:02Z","closed_at":null,"body":"I heard about JOML today, and as I'm always on the look out for a good math library have been looking over it.\r\n\r\nI guess my one concern (and this was an issue with vecmath too) is that there is no safe way to have a constant of any of the JOML types. Because all the class variables are public they are always mutable. So something like:\r\n\r\n```java\r\npublic static final Vector3f UP = new Vector3f(0, 1, 0);\r\n```\r\n\r\nIs always at risk of unintentional (or malicious) modification. (public variables also prevent injecting byte code to intercept value changes as that requires the use of setters, although that is not an issue for me as such).\r\n\r\n\r\nPossible approaches to address, in order of ascending complexity:\r\n\r\n### 1. Completely separate immutable types\r\n\r\nThis could be done outside of JOML - having a separate class of each type that is immutable, and can produce the JOML class as needed.\r\n\r\nDownside is object allocation.\r\n\r\n\r\n### 2. Make class variables private, add accessor methods\r\n\r\nsomething like\r\n\r\n```java\r\nprivate float x, y, z;\r\n\r\npublic float x() {\r\n  return x;\r\n}\r\n\r\npublic void x(float value) {\r\n  x = value;\r\n}\r\n```\r\n\r\nThis would allow a subclass to prevent changes by throwing exceptions on usage of method that would modify the class. The subclasses would still be usable in expected ways though such as ```v.add(UP)```.\r\n\r\nDownside is possibility of accidental leakage of immutable types into mutable context, resulting in a crash down the track when an attempt is made to mutate them. At least that is an obvious issues as opposed to the accidental alteration of a constant which can be hard to debug.\r\n\r\n\r\n### 3. Read-only base interface\r\n\r\nA 'trick' which I came up with that was used by the [TeraMath](https://github.com/MovingBlocks/TeraMath) library:\r\n\r\nFirst, you have an interface that provides the non-modifying methods of the type:\r\n\r\n```java\r\npublic interface Vector3fConst {\r\n   float x();\r\n   float y();\r\n   float z();\r\n   \r\n   float length();\r\n}\r\n```\r\n\r\n(this could also be an abstract class, with methods like length implemented in terms of the variable accessor methods)\r\n\r\nthen you have the mutable implementation\r\n\r\n```java\r\npublic final class Vector3f implements Vector3fConst {\r\n   public float x, y, z;\r\n   \r\n   public Vector3f set(Vector3fConst other) {\r\n      x = other.x();\r\n      y = other.y();\r\n      z = other.z();\r\n      return this;\r\n   }  \r\n}\r\n```\r\n\r\nThis provides a few benefits:\r\n * Method signatures clearly indicate whether they mutate a vector argument. If you send a Vector3f to the set method, you know it will not be modified.\r\n * It is possible to implement a true immutable vector to guarantee that the user won't just cast the value to the mutable implementation. This won't have a bunch of mutating methods that throw exceptions.\r\n * Also helps prevent accidental sharing of values between contexts. If you have the method\r\n\r\n```java\r\nvoid setEntityPosition(Vector3f newPosition)\r\n```\r\n\r\nThere is always the worry that it does\r\n```java\r\nposition = newPosition;\r\n```\r\ninstead of the desired\r\n```java\r\nposition.set(newPosition);\r\n```\r\n\r\nWith the signature\r\n```java\r\nvoid setEntityPosition(Vector3fConst other);\r\n```\r\n\r\nyou know even if it is shared it won't be modified at least.\r\n\r\nDownside is the method calls required access the values, the extra complexity of the class model, and without the actual immutable type it is only a soft guarantee of immutability. Also it is sort of dragging C++ behaviors into Java, which may be confusing.\r\n\r\n\r\n\r\nAnyway, just wanted to share these thoughts and ideas.  I don't know whether these sorts of concerns are within the scope of JOML or not."},"comment":{"url":"https://api.github.com/repos/JOML-CI/JOML/issues/comments/136140839","html_url":"https://github.com/JOML-CI/JOML/issues/52#issuecomment-136140839","issue_url":"https://api.github.com/repos/JOML-CI/JOML/issues/52","id":136140839,"user":{"login":"immortius","id":1388872,"avatar_url":"https://avatars.githubusercontent.com/u/1388872?v=3","gravatar_id":"","url":"https://api.github.com/users/immortius","html_url":"https://github.com/immortius","followers_url":"https://api.github.com/users/immortius/followers","following_url":"https://api.github.com/users/immortius/following{/other_user}","gists_url":"https://api.github.com/users/immortius/gists{/gist_id}","starred_url":"https://api.github.com/users/immortius/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/immortius/subscriptions","organizations_url":"https://api.github.com/users/immortius/orgs","repos_url":"https://api.github.com/users/immortius/repos","events_url":"https://api.github.com/users/immortius/events{/privacy}","received_events_url":"https://api.github.com/users/immortius/received_events","type":"User","site_admin":false},"created_at":"2015-08-30T14:04:02Z","updated_at":"2015-08-30T14:04:02Z","body":"I guess I agree that ideally math types would be value types, which Java doesn't support (without customising the JVM, using Scala ? or other shenanigans at least). So any approach taken will make sacrifices in some area. However I think the gap can be closed a bit without having to do something major like switch to immutable-only types or a copy-on-write approach.\r\n\r\nI hadn't even thought of copy-on-write semantics, and I imagine that it would represent a pretty severe change in API if nothing else. I think the standard, mutable JOML objects and their API are fine - and are actually excellent in the majority of situations. I assume you wouldn't want to make large scale breaking changes to the API. In that regard approach 2 fails, since it requires getting rid of all the public variables.\r\n\r\nI think the advantage of approach 3 is that the API for the existing JOML objects would remain the same, except \r\n\r\n1. they would inherit an interface which defines just the non-mutating methods.\r\n2. some of their methods would change to take instances of the interfaces instead of the actual objects, where they don't need to mutate them.\r\n3. they gain an accessor method for each parameter\r\n\r\nBut they can keep their public variables (thus maintaining the readability benefit), and they can continue to be used the same way as previously. But the interface allows an alternative implementation with no modification allowed, which can still be passed to operations on the standard implementation. The alternative implementation would not itself have any mutating operations.\r\n\r\nIf it would help I could PR an example of what I mean? Or if you are not interested that is also fine.\r\n"}}