digitalmars.D - RFC: patch statement
- Dejan Lekic (34/34) Apr 03 2017 I know people her do not like to see proposals that change (add
- Biotronic (42/76) Apr 03 2017 We can already do that. Proof of concept:
- Minty Fresh (26/60) Apr 03 2017 It looks like what you're trying to do is set up object mocks for
I know people her do not like to see proposals that change (add stuff to) the language. However, I strongly feel that for the testing purposes D should provide means to patch any object (no matter whether it is final or not!). Therefore I wonder what people think of adding a `patch(obj) {}` or perhaps change the semantics of the `with(obj) {}` so unittest writers can modify the object and set values. The patch keyword would work ONLY inside unittest {} blocks AND inside functions annotated with test annotation. Imagine we have: int myFun(Person person) { /* some logic here */ } unittest { auto p = new Person() /* does not really matter which constructor we use */ patch(p) { // here we can modify ANY attribute, no matter whether it is private or public p.fname = "Nikola" p.sname = "Tesla" } auto res = myFun(p) // do some assertions here } Similarly: test void test_myFun() { // same code as in the unittest above. } I do not even know if patch() {} statement is even possible, that is the whole point of writing this, so people can enlighten me... :) As I said in the introduction paragraph, for this purpose the semantics of the with statement could be changed, but I prefer a different keyword (patch) to be honest.
Apr 03 2017
On Monday, 3 April 2017 at 11:16:57 UTC, Dejan Lekic wrote:I know people her do not like to see proposals that change (add stuff to) the language. However, I strongly feel that for the testing purposes D should provide means to patch any object (no matter whether it is final or not!). Therefore I wonder what people think of adding a `patch(obj) {}` or perhaps change the semantics of the `with(obj) {}` so unittest writers can modify the object and set values. The patch keyword would work ONLY inside unittest {} blocks AND inside functions annotated with test annotation. Imagine we have: int myFun(Person person) { /* some logic here */ } unittest { auto p = new Person() /* does not really matter which constructor we use */ patch(p) { // here we can modify ANY attribute, no matter whether it is private or public p.fname = "Nikola" p.sname = "Tesla" } auto res = myFun(p) // do some assertions here } Similarly: test void test_myFun() { // same code as in the unittest above. } I do not even know if patch() {} statement is even possible, that is the whole point of writing this, so people can enlighten me... :) As I said in the introduction paragraph, for this purpose the semantics of the with statement could be changed, but I prefer a different keyword (patch) to be honest.We can already do that. Proof of concept: // ======================= module bar; class A { private int n; public int GetN() { return n; } } // ======================= module foo; import bar; void main() { import std.stdio : writeln; auto a = new A(); assert(a.GetN() == 0); with (patch(a)) { // Look ma, magic! n = 3; } assert(a.GetN() == 3); } auto patch(T)(T value) { return Patch!T(value); } struct Patch(T) { T _payload; mixin PatchFields!T; } mixin template PatchFields(T, int __n = -1) { static if (__n == -1) { mixin PatchFields!(T, T.tupleof.length-1); } else { enum name = __traits(identifier, T.tupleof[__n]); mixin("auto "~name~"(U)(U value) { _payload.tupleof[__n] = value; }"); static if (__n > 0) { mixin PatchFields!(T, __n-1); } } }
Apr 03 2017
On Monday, 3 April 2017 at 11:16:57 UTC, Dejan Lekic wrote:I know people her do not like to see proposals that change (add stuff to) the language. However, I strongly feel that for the testing purposes D should provide means to patch any object (no matter whether it is final or not!). Therefore I wonder what people think of adding a `patch(obj) {}` or perhaps change the semantics of the `with(obj) {}` so unittest writers can modify the object and set values. The patch keyword would work ONLY inside unittest {} blocks AND inside functions annotated with test annotation. Imagine we have: int myFun(Person person) { /* some logic here */ } unittest { auto p = new Person() /* does not really matter which constructor we use */ patch(p) { // here we can modify ANY attribute, no matter whether it is private or public p.fname = "Nikola" p.sname = "Tesla" } auto res = myFun(p) // do some assertions here } Similarly: test void test_myFun() { // same code as in the unittest above. } I do not even know if patch() {} statement is even possible, that is the whole point of writing this, so people can enlighten me... :) As I said in the introduction paragraph, for this purpose the semantics of the with statement could be changed, but I prefer a different keyword (patch) to be honest.It looks like what you're trying to do is set up object mocks for unit testing. In general, I find that well designed libraries provide such tools for testing, either in the form of factory functions or some other means of constructing mocks for test builds. I try to follow such patterns myself. Getting back to the immediate subject: You can already grant write access to whatever attributes with a bit of conditional compilation. Notably, defining accessors that exist only for unittest builds. You could even go so far as to define a generalized one, ie. version(unittest) { void patch(string attr, T)(Person p, T value) { __traits(getMember, p, attr) = value; } } And then, elsewhere: // Given p is some Person. p.patch!"fname" = "Nikola"; p.patch!"sname" = "Tesla"; So long as this is defined in the same module as the type, it'll be able to access protected and private fields.
Apr 03 2017