0

But how does a computer really do a function call? The expression(), term(), and primary() functions from Chapters 6 and 7 are perfect for illustrating this except for one detail: they don’t take any arguments, so we can’t use them to explain how arguments are passed. But wait! They must take some input; if they didn’t, they couldn’t do anything useful. They do take an implicit argument: they use a Token_stream called ts to get their input; ts is a global variable. That’s a bit sneaky. We can improve these functions by letting them take a Token_stream& argument. Here they are with a Token_stream& parameter added and everything that doesn’t concern function call implementation removed. First, expression() is completely straightforward; it has one argument (ts) and two local variables (left and t):

double expression(Token_stream& ts)
{
double left = term(ts);
Token t = ts.get();
// . . .
}

Second, term() is much like expression(), except that it has an additional local variable (d) that it uses to hold the result of a divisor for '/':

double term(Token_stream& ts)
{
double left = primary(ts);
Token t = ts.get();
// . . .
case '/':
{
double d = primary(ts);
// . . .
}
// . . .
}

I just wanna know what the point of doing this exactly was? Before making the functions take a reference argument ts was just a global object and the functions looked like this:

double term()
    {
    double left = primary();
    Token t = ts.get();
    // . . .
    case '/':
    {
    double d = primary(ts);
    // . . .
    }
    // . . .
    }

Like just what is the point of doing this? We didn't need arguments why did the writer decide to add reference arguments to each function?

jaylse2
  • 71
  • 4
  • Does this answer your question? https://stackoverflow.com/questions/484635/are-global-variables-bad – 463035818_is_not_an_ai Oct 22 '21 at 13:58
  • No I know why global variables aren't the best but here if I do the thing with passing references as arguments am I not gonna need a global variable to pass anyways? Like a global object of type Token_stream? How else am I gonna pass something in? – jaylse2 Oct 22 '21 at 14:00
  • no. The parameter can be a local variable, it does not need to be a global. – 463035818_is_not_an_ai Oct 22 '21 at 14:00
  • 3
    You are using a terrible reference. If they got to chapter 6 and 7 while using global variables, they are setting extremely bad habits. You should have switched to a good book 6 chapters ago. – Jeffrey Oct 22 '21 at 14:02
  • 2
    The question to ask yourself is "why use globals if you can pass arguments?", not "why pass arguments if you can use globals?" – molbdnilo Oct 22 '21 at 14:06
  • Usually the reason to **not** make something a global variable is so that you can have more than one of it. – user253751 Oct 22 '21 at 14:21
  • I highly recommend learning how to view or export the assembly language for a function. Also, learn how to read the assembly language for your platform. The assembly language will show how functions are called. – Thomas Matthews Oct 22 '21 at 15:16
  • Also to the guy saying to get a different book https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list it literally says PPP is one of the best books for beginners so idk – jaylse2 Oct 22 '21 at 18:21

2 Answers2

1

[...] I know why global variables aren't the best but here if I do the thing with passing references as arguments am I not gonna need a global variable to pass anyways?

No.

You can pass a global variable, but you don't have to:

int main() {
    Token_stream ts;   // <- not a global
    term(ts);
}

or

void foo() {
     Token_stream ts;  // <- not a global either
     term(ts);
}

int main() {
    foo();
}

If you consider only double term(Token_stream& ts) in isolation then it doesn't matter if a global or not is passed as parameter. One main reason to write functions is that functions can be read/understood/tested/debugged in isolation. All you need is some paramters you can pass. With double term() none of this is the case, because it is accessing global state. It is just spaghettis in disguise.

As mentioned in comments, the book you are using is taking an odd route. Instead of using globals as the default and then trying to argue why pass parameters instead, one should rather pass arguments to functions and only when there are good reasons use globals (there are almost never good reasons).

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
1

Like just what is the point of doing this?

I want to answer this part.

Imagine you have

Token_stream ts;

int main() 
{
    term(); //accesses global ts
    term(); //accesses global ts
}

and you are happy with this program. A few weeks later you want two token streams:

Token_stream ts1;
Token_stream ts2;


int main() 
{
    // first feature
    term(); // you want this to accesses global ts1
    term(); // you want this to accesses global ts1

    // second feature
    term(); // you want this to accesses global ts2
    term(); // you want this to accesses global ts2
}

How are you going to implement this ? Suddenly, you need two globals and in order to change the usage of your code, you need to go in and modify term itself.

This makes your code hard to use, hard to maintain and especially hard to test. Consider the alternative:

int main() 
{
    Token_stream ts1; 
    Token_stream ts2; 

    term(ts1);
    term(ts1);

    term(ts2);
    term(ts2);
}

And, most importantly, no changes were needed to term, to have a second Token_stream.

Jeffrey
  • 11,063
  • 1
  • 21
  • 42
  • 1
    How are you going to implement this ? simple, copy all code in `term` to a second function called `term2` and change all access to `ts` to accessing `ts2` :D. I have actually seen lots of code written like that – 463035818_is_not_an_ai Oct 22 '21 at 14:13
  • 1
    @463035818_is_not_a_number :-) for OP's benefit's, though, you should tag this or something. – Jeffrey Oct 22 '21 at 15:50