-1

Sometimes I need to get variable variable, that can be accessed from any place of code. But I often hear that global variables are bad. What is the best practice in D for such case?

Now my code look like:

string roothtml;
static this()
{
    roothtml = buildPath(getcwd, "html");
}

void main()
{
//
}

Is it's good or bad practice?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Dmitry Bubnenkov
  • 9,415
  • 19
  • 85
  • 145
  • I think there is an exception in every language. Settings are often stored in "global" variables. It's best to keep global variables read only if possible, though. – Millie Smith Dec 08 '15 at 07:45
  • Usually they're bad, because you do not have proper control about when and where they get accessed from. However D can counter-attack that with properties. – Bauss Dec 08 '15 at 08:15
  • @Milie, Bauss thanks, but could you look at my source example in comment below (after rcorre answer). Maybe you can suggest me something? – Dmitry Bubnenkov Dec 08 '15 at 14:05
  • Possible duplicate of [Are global variables bad?](http://stackoverflow.com/questions/484635/are-global-variables-bad) – Colonel Thirty Two Dec 09 '15 at 14:02

2 Answers2

2

Global variables are problematic for a few reasons.

  • It's harder to track where variables are coming from when you're reading. This makes it harder to understand a function using globals.
  • It's harder to track where a variable is used. This makes it harder to modify how your global variables should be used.
  • It's more awkward to inject test data and test stubs.
  • Test state will spill over to other tests.
  • __gshared globals require locking or immutability.
  • Thread-local globals are thread-local, so you can't propagate writes to all threads.
  • Any globals require you to think about whether you want it thread-local or __gshared.
  • If you need to convert your single-tenant application into a multi-tenant one, that will be painful if you're using global variables. And it's more common than you probably suspect.
  • You have to be careful not to build with -unittest when running your application so you don't trash global state initialized in a static constructor.

On the plus side, it's convenient that you don't have to pass global state everywhere. You don't have to use method to method object refactorings as often. You don't have to bring in a dependency injection system. It's very convenient when it's not biting you.

dhasenan
  • 1,177
  • 7
  • 15
1

It depends on what you really mean by 'global'. In the example above, I'd say its fine. You appear to be showing a main module, which probably shouldn't be imported by anything. In other words, it isn't really global, it is local to the main module. It really isn't so different from

class Main {
  private string _roothtml;
  static this() { _roothtml = buildPath(getcwd, "html"); }
  void run() { }
}

Even if it isn't really your main, D's module system offers protections of its own. Just stick a private on roothtml to encapsulate it within the module (it wouldn't hurt to do this in your main module anyways, just to be clear).

A pattern like this is widely employed in the source code of git. Rather than having a single main module that invokes a function for a given command, you have many main functions -- one for each top-level command.

For example, take a look at upload-pack.c.

See those variables declared at the top of the source file? Would the code have been any clearer or safer if they were wrapped in a class in typical OOP style or of explicitly passed to each function in a more purely functional style?

Each source file acts as a unit of encapsulation for a given command. This style is not always appropriate, but in the case of a program that can be thought of as a set of distinct commands, it can be cleaner than the alternatives.

Ultimately, the answer will be specific to the context, your given project, and your personal style. Generally speaking, cross-module globals are something to be looked on with suspicion, but module-level variables can sometimes be cleaner than the alternatives.

rcorre
  • 6,477
  • 3
  • 28
  • 33
  • could you help me in next example: http://www.everfall.com/paste/id.php?z6jzf0xluqu0 I can't undserstand how to check if user is admin. On line 93 I am trying write if user is admin or not. But setting this variable I am doing at 280 line, and declaration in main (line 50). In this case what would be best solution? – Dmitry Bubnenkov Dec 08 '15 at 13:48
  • `static this` -> `this`. Yours isn't appreciably better because it's not offering any hooks for a test to inject state and because the value is effectively immutable. Change those and you get a more complex but more testable (and more safely testable) solution. The complexity may not be justified in some situations. – dhasenan Dec 09 '15 at 05:07
  • I wasn't suggesting the class as an alternative, I was trying to show that a module actually offers class-like encapsulation of its own. Now that I look back at my answer its admittedly a bit confusing... – rcorre Dec 09 '15 at 13:14