Jump to page: 1 2
Thread overview
global vs context variable
Dec 11, 2013
luka8088
Dec 11, 2013
monarch_dodra
Dec 11, 2013
luka8088
Dec 11, 2013
QAston
Dec 11, 2013
luka8088
Dec 11, 2013
monarch_dodra
Dec 11, 2013
luka8088
Dec 11, 2013
Ary Borenszweig
Dec 11, 2013
Shammah Chancellor
Dec 11, 2013
luka8088
Dec 11, 2013
Artur Skawina
December 11, 2013
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?


December 11, 2013
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.

"write" is really just a global helper/shortcut function that calls "stdout.write". If the user wants to customize this, then it's really no more complicated than doing a write to a named stream, which represents the global out, which may or may not be stdout:

auto myGlobalOut = stdout;
myGlobalOut.write(); //Writes to console (technically, "standard output")

//Change the global output context
myGlobalOut = File("out.txt", "w");
myGlobalOut.write(); //Writes to file

--------

I'm not really sure I understood the rest of what you posted though, so I can't make any comments on that.
December 11, 2013
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.
December 11, 2013
On 2013-12-11 08:21:35 +0000, luka8088 said:

> Examples using such library:
> 
> void writeOutput () {
>   writeln("example output");
> }
> 
> void main () {
> 
>   writeOutput();
> 
>   standardOutputContext(file("example.txt"), {
>     writeOutput();
>   });
> 
> }


What does this method have over just using:

with(file("example.txt"))
{
	writeln("Foo");
}

December 11, 2013
On 11.12.2013. 9:30, monarch_dodra wrote:
> 
> "write" is really just a global helper/shortcut function that calls "stdout.write". If the user wants to customize this, then it's really no more complicated than doing a write to a named stream, which represents the global out, which may or may not be stdout:
> 
> auto myGlobalOut = stdout;
> myGlobalOut.write(); //Writes to console (technically, "standard output")
> 
> //Change the global output context
> myGlobalOut = File("out.txt", "w");
> myGlobalOut.write(); //Writes to file

Yes. That is exactly what this kind of approach is all about. In practice I found a need to temporarily change myGlobalOut while keeping in mind that recursion could be used and in most cases a stack was required. You also need to make sure that stack is pop'ed properly (even in case of throwing) so generally there is some work to be done. I think that this kind of approach would be much more user friendly if a library support was introduced.

> 
> --------
> 
> I'm not really sure I understood the rest of what you posted though, so I can't make any comments on that.

Take MVC for example. Most frameworks either support global variables or setting a controller properties for stuff that needs to be accessible globally. I have seen database connections being a property of a controller, which if you think about it makes no sense, but it was the most pragmatical way to do it in order to make database connection "globally" accessible without setting is as a global variable.

December 11, 2013
On 11.12.2013. 10:53, QAston wrote:
> 
> 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.

Yeah, and it always keeps pooping right up!

> 
> 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.

I was thinking about such issues and think they are all solvable. I concluded that I should present this issues as simple and possible to check out the general interest first.

> 
> 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.

Yes. Not only that swapping would need to permitted but also only same type values could be swapped. D makes sure of that.

December 11, 2013
On 11.12.2013. 12:14, Shammah Chancellor wrote:
> On 2013-12-11 08:21:35 +0000, luka8088 said:
> 
>> Examples using such library:
>>
>> void writeOutput () {
>>   writeln("example output");
>> }
>>
>> void main () {
>>
>>   writeOutput();
>>
>>   standardOutputContext(file("example.txt"), {
>>     writeOutput();
>>   });
>>
>> }
> 
> 
> What does this method have over just using:
> 
> with(file("example.txt"))
> {
>     writeln("Foo");
> }
> 

It works with deep nesting without the need to pass the context as a function argument:

void writeOutput () {
  writeln("example output");
}

void f2 () {
  writeOutput();
}

void f1 () {
  f2();
}

void main () {

  f1();

  standardOutputContext(file("example.txt"), {
    f1();
  });
}

December 11, 2013
On Wednesday, 11 December 2013 at 12:58:54 UTC, luka8088 wrote:
> On 11.12.2013. 10:53, QAston wrote:
>> 
>> 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.
>
> Yeah, and it always keeps pooping right up!

I hate it when issues just keep pooping up. So rude!
December 11, 2013
On 11.12.2013. 15:47, monarch_dodra wrote:
> On Wednesday, 11 December 2013 at 12:58:54 UTC, luka8088 wrote:
>> Yeah, and it always keeps pooping right up!
> 
> I hate it when issues just keep pooping up. So rude!

Lol, popping xD
December 11, 2013
On 12/11/13 12:54 PM, luka8088 wrote:
> On 11.12.2013. 15:47, monarch_dodra wrote:
>> On Wednesday, 11 December 2013 at 12:58:54 UTC, luka8088 wrote:
>>> Yeah, and it always keeps pooping right up!
>>
>> I hate it when issues just keep pooping up. So rude!
>
> Lol, popping xD
>

shit happens
« First   ‹ Prev
1 2