AlexeyDmitriev / JHelper

GNU Lesser General Public License v3.0
119 stars 31 forks source link

How use global variable? #97

Closed emli closed 5 years ago

emli commented 5 years ago

Hi @AlexeyDmitriev

As you know CP programmers love use global variables. With jhelper we need reinitialize global variable. What it the better solution for this situation?

AlexeyDmitriev commented 5 years ago

Well, you can use variables inside the class (they are initialized before each test (but not between tests in multitest)) e.g

class TaskA {
   int global = 0; 

   void solve(...) {...}
};

Of course, in that case you will need to declare member functions (functions inside the class), not free functions

AlexeyDmitriev commented 5 years ago

Also, one trick you can use is to use lambdas with capture instead of functions

void solve() {
   int x = 5;
   auto f = [&]() {
       // you can use x here, it becomes effectively global
   }
}

But overall, I think passing things as parameters to functions is good, it helps with debugability. You can try that.

emli commented 5 years ago
        int a[100];
        auto f = [&]() {
            cout << x << endl;
            cout <<a[1] << " " << a[99] << endl;
        };
        f();

Variables getting random values by default.

AlexeyDmitriev commented 5 years ago

try int a[100] = {}; or better yet vector<int> a(100);

AlexeyDmitriev commented 5 years ago

Hope that helps

emli commented 5 years ago

Hi @AlexeyDmitriev !

I think jhelper testing like this;

Solution solution;

solution.run() - calling this function many times.

Why not make like this.

Solution solution_for_first_test,solution_for_second_test;

Initialize variables is not friendly not sport programming.

AlexeyDmitriev commented 5 years ago

Well, there's 3 reasons for this design I see: 1) This way it's easier to embed it to CLion: you have 1 task -- 1 application run as normally 2) This way it's easier to aggregate result of all runs: to check whether all outputs are correct, to print max time, etc 3) This way it's faster in case of multiple small tests because you don't need to have a startup time for each test.

Besides, I don't think multiprocess option gives an advantages because it's not that hard to initialise variables: just add {} to them. Maybe you are just used to global variables and not used

Maybe it may help to think of it this way: you are writing a function that should calculate something but you don't know when your function will be called. Maybe it's not the way one usually thinks when he writes only sport programming code, but I think it should be useful to try. For example, imagine you are a developer of standard library and need to implement a std::sort function. You may do anything you need in it (have variables, other functions) but after you return, input array should became sorted and nothing else should change. It may seem like a big restriction but I don't think it really is. When also applied to subparts of the code, it also makes reasoning about the code easier. The same applies to classes, e.g if you have a class for segment tree and not use global variables, you can reuse it in the problem where you need 5 independent segment trees or apply to different algorithms that happen. You can find some inspiration in my spcppl library (e.g for your own library for contests).

Also, you may check my submissions e.g on CF and see that it happens quite rare that I actually use global variables (or equivalently, variable inside a solution class)

On somewhat unrelated note: I recommend to switch from arrays[MAXN] to vectors (I used arrays before too but switched eventually). It makes debugging much easier, especially if you use sanitizers or flags to debug vector access locally. Contrary to popular belief, it (almost?) doesn't gives you a performance hit if used correctly (if you always create it with sizes when size is known, you may also see examples in my submissions). Compare int a[101010]; vs vector<int> v(n);. Not much longer and helps to find bugs

emli commented 5 years ago

@AlexeyDmitriev thanks for well explained answer

emli commented 5 years ago

https://github.com/emli/competitive/blob/master/tasks/spoj/KeyTask.cpp#L32

Found another solution

AlexeyDmitriev commented 5 years ago

I am glad you find solution that suits you, but I don't really understand, what you win here compared to https://github.com/AlexeyDmitriev/jhelper-example-project/blob/patch-1/tasks/spoj/KeyTask.cpp

AlexeyDmitriev commented 5 years ago

PS: you can implement reading till zeroes so that solve() only needs to solve one subtest, not all of them

emli commented 5 years ago

Your solution is short and good. But minus is that you can't create big arrays in class. You should increase stack size in cmake file that actually I can't do it

AlexeyDmitriev commented 5 years ago

That's a problem I didn't think of. I think you can increase stack like this if you use linux/macosx in your run.template

emli commented 5 years ago

Do you any how to this make in cmake file?

AlexeyDmitriev commented 5 years ago

I don't think it's possible unless you are on windows