Programming Challenge - count capital letters in a string

Here you can talk about anything related to BBC BASIC, not covered in another category
User avatar
JeremyNicoll
Posts: 72
Joined: Sun 26 Jul 2020, 22:22
Location: Edinburgh

Re: Programming Challenge - count capital letters in a string

Post by JeremyNicoll »

hellomike wrote: Sat 04 Mar 2023, 13:07 It really is totally beyond the point whether you would or wouldn't write code like this.

The issue is pure a technical one of how the interpreter works internally. I think the snippet of code that I provided illustrates exactly why MID$() and similar functions, internally first make a copy and doing the actual instruction on the copy.
Fair enough.

Does the interpreter protect formal parameters in the same way if a user writes a function of their own? If not, why not?
User avatar
hellomike
Posts: 184
Joined: Sat 09 Jun 2018, 09:47
Location: Amsterdam

Re: Programming Challenge - count capital letters in a string

Post by hellomike »

I would think so but of course only Richard can truly answer this.
Hated Moron

Re: Programming Challenge - count capital letters in a string

Post by Hated Moron »

JeremyNicoll wrote: Sat 04 Mar 2023, 10:48 I would have expected the code inside however it is that you implement MID$ to validity check the values of 'start' and 'length'...
Of course it does. Anyway it's irrelevant to the question under discussion, nobody has suggested that any of the parameters is 'out of range'.
Also as the formal parms for MID$ are local to that function...
What do you mean by "local to that function"? Any or all of the parameters could be 'non-local' if they include user-defined functions:

Code: Select all

      result$ = MID$(FNsource, FNstart, FNcount)
Of course the interpreter would be made much simpler if one were to require that user-defined functions may not be used as the parameters to other functions, but then it would neither be BBC BASIC, nor any dialect of BASIC that I've ever encountered.
I'd welcome an example of an edge case where this could happen.
Here's a little program I wrote to check whether it misbehaves in other versions of BBC BASIC, including the original 6502 version from 1981. It doesn't, because they have all been coded with that possibility in mind:

Code: Select all

   10 global$ = "AAAAAAAA"
   20 PRINT MID$(global$, FNstart, FNcount)
   30 END
   40
   50 DEF FNstart
   60 global$ = "BBBBBBBB"
   70 = 2
   80
   90 DEF FNcount
  100 global$ = "CCCCCCCC"
  110 = 4
You can't tell me that in any sane programming language the correct result would be anything other than "AAAA".
When you say "If /you/ do it naively" ... do you mean "you" as in the implementer of the language?
I'm using "you" in the normal sense of "one", or "anybody" or "the programmer". What else could I have meant?
It's completely irrelevant that - lexically - the names of the formal parameters happen to match any of those used,...
It's relevant to the implementation of the interpreter, that's the whole point. A naïve implementation will copy the first 'actual' parameter into the first 'formal' parameter, then the second 'actual' parameter into the second 'formal' parameter and so on. That will fail in the example I gave.

If you are suggesting that all programmers of interpreters are so familiar with the issue that they would never make such a mistake, then it's you who is being naïve!
I don't see how this theoretical example (of how not to implement parameter passing) has any bearing on the reason that MID$ was slow in the programming challenge.
The connection is this: both the MID$() example and the parameter-passing example require the source string(s) to be temporarily copied, typically onto the stack. It is the time taken for this copy or copies that can be significant.
In general I think I'd expect a programmer [to be] aware that the A$ that will be passed to MID$ isn't necessarily the same as A$ was prior to the statement containing the call.
Really? Can you name any programming language which has such a requirement? BASIC, which is supposedly a language for 'beginners' and is expected to behave in a common-sense way, does not place any such expectation on the programmer. If he passes a string as a parameter to a built-in function, he should (and can) expect that to be the string on which the function ultimately operates.
Is there anywhere in the BBC BASIC manual where you describe this potential problem?
It isn't a problem in BBC BASIC!! It's you who are arguing that the extra work that the interpreter does to avoid the problem isn't necessary, and that the programmer should be aware of, and if necessary work around, the resulting misbehaviour himself. Then there would be a need to document it!
Hated Moron

Re: Programming Challenge - count capital letters in a string

Post by Hated Moron »

JeremyNicoll wrote: Sat 04 Mar 2023, 14:02 Does the interpreter protect formal parameters in the same way if a user writes a function of their own? If not, why not?
I don't understand the question. Please give an example of a user-defined function that requires such 'protection'.
User avatar
JeremyNicoll
Posts: 72
Joined: Sun 26 Jul 2020, 22:22
Location: Edinburgh

Re: Programming Challenge - count capital letters in a string

Post by JeremyNicoll »

Hated Moron wrote: Sat 04 Mar 2023, 15:13
JeremyNicoll wrote: Sat 04 Mar 2023, 10:48 I would have expected the code inside however it is that you implement MID$ to validity check the values of 'start' and 'length'...
Of course it does. Anyway it's irrelevant to the question under discussion, nobody has suggested that any of the parameters is 'out of range'.
Before someone-else explained how evaluation of a numeric parameter could change MID$'s first parm, that was all that had occurred to me.

Hated Moron wrote: Sat 04 Mar 2023, 15:13
JeremyNicoll wrote: Sat 04 Mar 2023, 10:48 Also as the formal parms for MID$ are local to that function...
What do you mean by "local to that function"?
I meant in the same sense that's in your documentation, eg where, in the section "Formal and actual parameters" you said both that actual parm values are copied to formal ones, and then "Formal parameters are automatically made local to the procedure or function.".

My "local to" is your "made local".

Hated Moron wrote: Sat 04 Mar 2023, 15:13 Here's a little program I wrote to check whether it misbehaves in other versions of BBC BASIC, including the original 6502 version from 1981. It doesn't, because they have all been coded with that possibility in mind:

Code: Select all

   10 global$ = "AAAAAAAA"
   20 PRINT MID$(global$, FNstart, FNcount)
   30 END
   40
   50 DEF FNstart
   60 global$ = "BBBBBBBB"
   70 = 2
   80
   90 DEF FNcount
  100 global$ = "CCCCCCCC"
  110 = 4
You can't tell me that in any sane programming language the correct result would be anything other than "AAAA".
I wouldn't be surprised if some languages deliberately or carelessly don't produce "AAAA".

Hated Moron wrote: Sat 04 Mar 2023, 15:13
JeremyNicoll wrote: Sat 04 Mar 2023, 10:48 It's completely irrelevant that - lexically - the names of the formal parameters happen to match any of those used,...
It's relevant to the implementation of the interpreter, that's the whole point. A naïve implementation will copy the first 'actual' parameter into the first 'formal' parameter, then the second 'actual' parameter into the second 'formal' parameter and so on. That will fail in the example I gave.
But surely the /names/ of the parameters shouldn't matter. It's their position in the parameter list that dictates which is copied where, surely?

Also (as I said, I 'm getting confused), you just said "A naïve implementation will copy the first 'actual' parameter into the first 'formal' parameter, then the second 'actual' parameter into the second 'formal' parameter and so on." But that seems to me to be what your own documentation says IS what happens; your sentence elsewhere(*) is "The value of the first parameter in the call to the procedure or function is passed to the first variable named in the parameter list in the definition, the second to the second, and so on."

* - http://www.bbcbasic.co.uk/bbcwin/manual/bbcwin2.html - at "Formal and actual parameters"

Hated Moron wrote: Sat 04 Mar 2023, 15:13
JeremyNicoll wrote: Sat 04 Mar 2023, 10:48 I don't see how this theoretical example (of how not to implement parameter passing) has any bearing on the reason that MID$ was slow in the programming challenge.
The connection is this: both the MID$() example and the parameter-passing example require the source string(s) to be temporarily copied, typically onto the stack. It is the time taken for this copy or copies that can be significant.
Yes, but that's standard parameter passing. I was under the impression that someone had said that an /extra/ copy was required.

I'll need to try and work what the difference between what I thought we were discussing and <reality> is.
Hated Moron

Re: Programming Challenge - count capital letters in a string

Post by Hated Moron »

JeremyNicoll wrote: Sat 04 Mar 2023, 16:43 My "local to" is your "made local".
Yes, but commonly (and it's the case in BBC BASIC) "making local" means 'making a copy on the stack'. And it's precisely the fact that MID$ makes a copy of the source string on the stack (resulting in it being slow if the string is large) that you have been arguing is unnecessary or unexpected.

You can't have it both ways: if you consider that 'making the parameters local' is the normal behaviour for a function, you shouldn't be surprised that it's exactly what MID$ does, making it slow. If you continue to express surprise that MID$ 'wastes time' copying the source string to the stack, you have to acknowledge that the parameters are no longer 'local'.
I wouldn't be surprised if some languages deliberately or carelessly don't produce "AAAA".
I would. And in different circumstances you would probably be the first to complain if BBC BASIC did so!
But surely the /names/ of the parameters shouldn't matter. It's their position in the parameter list that dictates which is copied where, surely?
That would be true only if the code inside the function had a separate namespace from the code outside the function. Some languages do work that way, and in that case the variable a$ outside the function is unrelated to the variable a$ inside the function, sharing only its name but not its storage.

But of course that's not how BBC BASIC (or most interpreted BASICs for that matter) work: there is just one global namespace, the variable a$ inside the function is the same variable a$ outside the function; they share both name and storage. It's why the LOCAL statement (and PRIVATE in the case of my versions) exists in BBC BASIC: if a function had a separate namespace they would be superfluous.
you just said "A naïve implementation will copy the first 'actual' parameter into the first 'formal' parameter, then the second 'actual' parameter into the second 'formal' parameter and so on." But that seems to me to be what your own documentation says IS what happens
The user documentation explains what happens in a conceptual way that is easy to understand, it doesn't pretend to describe the detailed internal processes that take place. Do you really think it would be helpful for the documentation to say: "The first 'actual' parameter is copied onto the stack, then the second 'actual' parameter is copied onto the stack, then the second 'formal' parameter is copied from the stack and finally the first 'formal' parameter is copied from the stack"?

That would be more technically accurate, but to make sense of it the user would have to understand what a stack is. The essence of BASIC is that complications of this sort are hidden from the user, and it just does 'the right thing'. Yes that means the documentation describes things in a simplified way that doesn't strictly represent what goes on under the hood, but that's how it should be for a 'beginners' language.

I think you once admitted that you never use BBC BASIC yourself, which probably explains your ignorance of so much that is key to the language.