On Wednesday, 11 December 2013 at 08:21:33 UTC, luka8088 wrote:
Hi everyone!
I would like to address the issue of global variables (or
states). In
general my opinion is that they are bad solely because they (in
most
cases) lack the ability of alternative values (or states) or
ability to
alter them in user friendly way.
For example, take write function from std.stdio. For a third
party
function that uses write to output to screen user is unable to
redirect
that output to, for example, file without altering third party
function's body. Or if there is a way it rarely user friendly.
For
example, in php there are function for buffering output but you
have to
manually start buffering and manually stop it. In python active
output
is a global variable and you are able to replace it with a
custom file
stream but you are responsible maintain a custom stack in case
of
recursion and switching it back to default output when no
longer needed.
There are also examples of loggers, database connections, etc.
I have a proposal to generalize this issue. Attached is a
example
library that implements context based approach and I would like
to see
this kind of library in phobos (std.context). It is very simple
and yet
in my experience it has shown to be very useful.
Examples using such library:
void writeOutput () {
writeln("example output");
}
void main () {
writeOutput();
standardOutputContext(file("example.txt"), {
writeOutput();
});
}
MVC example:
void databaseToView () {
auto result = db.query("select;");
view.populate(result);
}
void myAction () {
auto customView = new View();
viewContext(customView, {
databaseToView();
});
view.regionA.append(customView);
}
void main () {
dbContext(defaultDbConnection {
viewContext(defaultView, {
myAction();
});
});
}
I would like to add this to phobos and document it but I would
like to
know if this is desirable at all and to get a community
feedback.
Thoughts?
This issue is probably nearly as old as programming itself.
There are several sollutions already developed: dependency
injection (requires complex configuration rules), manually
passing deps as args (cumbersome), service locator or global
variables.
Your sollution as far as I understand it relies on swapping a
global variable when inside a context and restoring it
afterwards. While this would be perfectly fine in environment
where code is executed in OS threads, there will be a problem in
the case of Vibe.d which uses fibers. But I guess the problem is
solvable there aswell.
Just to note - you have to bind to globals at some point - what
if someone wants to swap writeln function whith his own (for
example to call logger, or for whatever reason)? Or he may want
to swap dbContext :).In my practice I make swappable only things
I think I'll need to swap in future.