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









Biotronic <simen.kjaras gmail.com> 