jack: (Default)
[personal profile] jack
The idea in my last post got a bit buried, so I thought it through some more. I'm still mulling it through, I'm not sure if it makes sense.

Imagine you have a computer game. What are your classes like? Often you have a top-level "program" class. And maybe a "current game" class and "current level" class. And a whole bunch of stuff for each object in the level (whether those are separate class types, or just structs with an enum for type, or whatever).

You often have some data or functionality which is specific to your program, but should be accessible in many parts of the program. Or specific to the current game, or current level. Eg. many different events may add a score. Everything might write to a log file. Commonly functions on objects want to look at other "nearby" objects.

Currently, you basically have a choice of two scopes of values which are available to a function. Global variables, and variables in the current class. What I'm suggesting is that two is the wrong number of scopes to have. If you have two, one or two more is likely to be useful.

Some data naturally lives in a level neither global, nor in in the current class, but in the "program" class. And is visible to all classes "in" the program class.

What does "in" mean? Possibly "declared with a special syntax referencing the program class". But it might be better to treat it like a namespace or module, that says "everything in here can only be used by this class (or compatible classes like mocks)", and all member functions get *two* hidden parameters, one for the program, and one for the "this" pointer. Or four, if you have "program", "current game", and "level".

It's easy to imagine your program and say, "but there'll only be one current game at once". But once you SAY that, you can imagine why there wouldn't be. And then any values associated with that need to not be just shoved in the program class or in global scope, but managed properly.

And you CAN provide them to the "children" classes by giving the child class a pointer to the correct parent . You definitely should decide what should be visible everywhere and what only needs to be some places. But I'm suggesting it would be *clearer* not to do that, but explicitly choose what should be shared.

ETA: Simon points me to a post of gerald-duck's I read ages go but seem to have partially re-invented: http://gerald-duck.livejournal.com/710339.html

Date: 2017-02-02 06:23 pm (UTC)
mtbc: photograph of me (Default)
From: [personal profile] mtbc
I don't know if this is remotely apropos but you remind me of Modula-3's partial revelations: https://www.cs.tut.fi/lintula/manual/modula3/modula-3/html/partial-rev/

Date: 2017-02-03 08:43 am (UTC)
ewx: (Default)
From: [personal profile] ewx
I'd been wondering about something related after one of your previous entries. In a lot of languages we have the ability for function arguments to take default values; how about we extend that to taking default values that are dependent on the scope they are called from?

Using C++ish syntax, and taking logging as a concrete example, I suggest:

void f(int a, int b, logger *l = auto);

...with the rule that if a auto argument is missing, and if there is an object with the same name and type in scope at the call point, that value is used. So:

void g() {
  logger *l = get_logger();
  //...
  f(a, b); // actually does f(a, b, l);
}

When you want to supply a different logger from the one you already had, you just supply the argument as usual.

Not sure how you extend the rule to languages where there aren't type annotations on function arguments. Maybe you do it on name alone, or maybe you grow up and add a type annotation syntax l-)