LB Booster
« RIGHT$() etc. with parameter side-effect »

Welcome Guest. Please Login or Register.
Jul 26th, 2017, 10:43am


Speed up Liberty BASIC programs by up to ten times!
Compile Liberty BASIC programs to compact, standalone executables!
Overcome many of Liberty BASIC's bugs and limitations!
LB Booster Resources
LB Booster documentation
LB Booster Home Page
LB Booster technical Wiki
Just BASIC forum
LB Umbrella forum
Liberty BASIC forum (the original)

« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: RIGHT$() etc. with parameter side-effect  (Read 220 times)
Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1247
xx RIGHT$() etc. with parameter side-effect
« Thread started on: Mar 23rd, 2017, 3:58pm »

Triggered by a discussion at the BBC BASIC forum I tried this program in LB 4 and LBB:

Code:
    global b$
    b$ = "good"
    print right$(b$, four())
    end

function four()
    b$ = "bad"
    four = 4
end function 

LBB prints 'good' but LB4 prints 'bad'. My personal opinion (as is evident from my choice of strings!) is that the LB 4 answer represents a bug - the side-effect of the function should not affect the result from right$() because "good" has already been passed as the first parameter - but your judgment may vary.

Worth noting the difference anyway.

Richard.
« Last Edit: Mar 23rd, 2017, 4:00pm by Richard Russell » User IP Logged

Rod
Junior Member
ImageImage


member is offline

Avatar




PM

Gender: Male
Posts: 86
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #1 on: Mar 23rd, 2017, 8:47pm »

Since everything is sequential we first pass global b$, "unnecessarily", in the function call to right$(). Then we call four() and as expected global b$ is available and is changed to "bad" globally. At which point the last sequential action is to return the right most value of global b$.

If the discussion is about b$ within the function being unique and not global then I get confused. Global is global?

Passing global values in any function should get a warning?
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1247
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #2 on: Mar 23rd, 2017, 9:53pm »

on Mar 23rd, 2017, 8:47pm, Rod wrote:
At which point the last sequential action is to return the right most value of global b$.

That's not how functions in Liberty BASIC are supposed to work (which I think you know, really). The parameters to an LB function are passed by value, not by reference, so the first parameter to the RIGHT$() function in the code I listed is the string "good", it's not the variable b$! The fact that the variable b$ gets modified at some subsequent point is irrelevant, what matters is the value of the first parameter at the time the function is called.

Hence the correct result is "good" as it is in LBB. In a language which passes parameters by reference (like QBASIC) you can argue that the subsequent modification of b$ should have an effect, but that's not the case in LB.

Quote:
Passing global values in any function should get a warning?

Why? Whether a variable is global or not has no bearing on its suitability as the parameter of a function. One of the valuable LBB extensions is to be able to pass a whole array as a parameter of a SUB or FUNCTION, but in Liberty BASIC arrays are always global!

Consider a trivial function which returns the square of a number. There's no reason to think you wouldn't want to find the square of a global variable; this works equally well in LB 4 and LBB of course:

Code:
    global Alpha, Beta
    Alpha = 1.2
    Beta = 3.4
    print square(Alpha), square(Beta)
    end

function square(n)
    square = n * n
end function 

Richard.
« Last Edit: Mar 23rd, 2017, 10:56pm by Richard Russell » User IP Logged

BrianM
New Member
Image


member is offline

Avatar




PM


Posts: 13
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #3 on: Mar 24th, 2017, 8:45pm »

It would appear that LB evaluates function calls in the parameter list before 'normal' parameters. Try running ...

Code:
global b$
    b$ = "good"
    print right$(b$, four())
    b$ = "good"
    print right$(nochange$(b$), four())
    end

function four()
    b$ = "bad"
    four = 4
end function

function nochange$(s$)
    nochange$= s$
end function
 


You should get the output (in LB 4.04) :-

bad
good

This seems wrong to me. Either evaluate parameters consistently left to right (sensible) or right to left (a bit odd) but not function calls first.

As a general rule it is bad practice to update global variables in a function.

Brian Matthews
User IP Logged

tsh73
Full Member
ImageImageImage


member is offline

Avatar




PM

Gender: Male
Posts: 196
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #4 on: Mar 24th, 2017, 9:03pm »

Quote:
As a general rule it is bad practice to update global variables in a function.

Huh? Where should I update them then?

But really if my code written so it depends from order of evaluation, I'm in trouble.
User IP Logged

BrianM
New Member
Image


member is offline

Avatar




PM


Posts: 13
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #5 on: Mar 24th, 2017, 9:30pm »

Ideally a function should calculator a value from the given parameters and should not change anything else (see pure functions on Wikepedia). This avoids unintended side effects. If it calculates a value and performs other processes then to my mind it should not be a function but a subroutine. Obviously rules are made to be broken and there will always be instances where it is pragmatic to update global or (preferably) static variables. For example in the implementation of iterators.

I agree with you in that LB is rather bizarre in the order of evaluation of parameters.

Brian
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1247
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #6 on: Mar 24th, 2017, 10:01pm »

on Mar 24th, 2017, 9:03pm, tsh73 wrote:
Huh? Where should I update them then?

If you want to change a 'global' variable in a function it's arguable that you should instead make it an ordinary variable and pass it as a BYREF parameter. True 'globals' should probably be reserved for constants (or at least values that are changed only in the 'main program').

But Liberty BASIC programs rarely achieve the highest standards of program design, not least because certain features of the language (such as arrays and structures always being global) make it impossible.

Richard.
« Last Edit: Mar 24th, 2017, 10:03pm by Richard Russell » User IP Logged

BrianM
New Member
Image


member is offline

Avatar




PM


Posts: 13
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #7 on: Mar 24th, 2017, 10:29pm »

Quote:
If you want to change a 'global' variable in a function it's arguable that you should instead make it an ordinary variable and pass it as a BYREF parameter.

I agree but beware. LB implements BYREF as a copy on entry to the sub/function and a copy back on return. It does not pass the address of the variable. Thus if you update a global variable as a parameter in a sub/function the global variable itself is not updated until the sub/function is exited. This has caught me out.

Brian
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1247
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #8 on: Mar 24th, 2017, 10:51pm »

on Mar 24th, 2017, 10:29pm, BrianM wrote:
This has caught me out.

It wouldn't catch me out - BBC BASIC has always worked the same way and it's therefore what I expect. Mind you BBC BASIC is more honest about the terminology: it uses 'RETURN' rather than 'BYREF' to emphasise that it's not an address being passed but that the parameter is updated on return.

Richard.
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1247
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #9 on: Mar 24th, 2017, 11:09pm »

Not surprisingly the same thing happens if you use BYREF rather than a global:

Code:
    b$ = "good"
    print right$(b$, four(b$))
    end

function four(byref a$)
    a$ = "bad"
    four = 4
end function 

Richard.
User IP Logged

Rod
Junior Member
ImageImage


member is offline

Avatar




PM

Gender: Male
Posts: 86
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #10 on: Mar 25th, 2017, 10:58am »

I can't see how the right$() function can be enacted without the four() function being processed first. If that function changes either a global variable, or byref, a passed variable that will happen during the function call or on its return.

I take the point that the variable may be passed as a copy but I am not sure that a copy is passed when the variable is global in LB. However, changing the variable in the function should result in the updated variable being sliced. Just my opinion, as the code can't mean to accomplish anything else.

But as has been said, there are easier ways to trip up.
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1247
xx Re: RIGHT$() etc. with parameter side-effect
« Reply #11 on: Mar 25th, 2017, 2:09pm »

on Mar 25th, 2017, 10:58am, Rod wrote:
I can't see how the right$() function can be enacted without the four() function being processed first.

I'm sure nobody is suggesting otherwise: of course all parameters must be 'evaluated' (i.e. converted to a numeric or string value) before being passed to the function that needs them. That's inherent in being 'passed by value'.

The point is that they should be evaluated in a 'sensible' and 'predictable' fashion, for example consistently left-to-right. Evaluating all the 'function' parameters before any of the 'scalar' parameters, which appears to be what LB does, is unexpected and breaks the 'rule of least astonishment'.

Quote:
I am not sure that a copy is passed when the variable is global in LB.

Two points to make there. Firstly whether the variable is global or not should not make any difference to the way it is passed to a function. In LB a global variable is one which is 'in scope' everywhere: both in the main program and within SUBs and FUNCTIONs. It is no less suitable as a parameter of a function than any other variable (that's not to say LB 4 doesn't treat globals differently: it does lots of peculiar things such as this bug!).

Secondly, as I demonstrated in a recent post, the problem persists in the absence of any global variables - using BYREF triggers exactly the same behavior.

One has to 'expect the unexpected' when using LB 4 because it has so many bugs and strange features. For example, also in respect of passing parameters to a function, this bug demonstrates that parameters aren't always passed 'by value' even though the documentation clearly states that they should be (in the absence of a BYREF).

If I'd realised just how much the actual behavior of LB 4 differs from what the documentation states, making it all but impossible to emulate accurately, I might not have set out to create LBB in the first place!

Richard.
User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

Donate $6.99 for 50,000 Ad-Free Pageviews!


This forum powered for FREE by Conforums ©
Sign up for your own Free Message Board today!
Terms of Service | Privacy Policy | Conforums Support | Parental Controls