I wonder how you type x = x+1 into a calculator and what result it shows.
For sure in mathematics x = x+1 can not be correct. x can not be x and x-1 at the same time. This is only possible if there exists a previous x value, and a next x value and in between happens some procedurale processing. Either by a Spin code or by typing it in a calculator.
And it's the same with
5 < x < 10
in mathematics this shows the possible range of x, but in a programming language it's something different. It's a serie of procedurale steps that execute from left to right.
An alternative here for SPIN2 is to create a pair of ternary instructions and a single constant (NA).
CLAMP lower value upper
CLAMPS lower value upper
When the upper or lower limit is not being used it can be replaced with NA. When the byte code compiler encounters the NA it can omit that operation. If only two operands are supplied an error can be thrown to ensure the programmer's intent is captured.
If no assignment is made the clamped result is placed in value.
An alternative here for SPIN2 is to create a pair of ternary instructions and a single constant (NA).
CLAMP lower value upper
CLAMPS lower value upper
When the upper or lower limit is not being used it can be replaced with NA. When the byte code compiler encounters the NA it can omit that operation. If only two operands are supplied an error can be thrown to ensure the programmer's intent is captured.
If no assignment is made the clamped result is placed in value.
That would be an interesting use of an operator, having multiple arguments.
All these efforts are like feeling our way around an invisible shape, without quite the proper tools and approach to conform our thought with syntax, or finally penetrate the shape. Everything we manage to implement is only a half-baked analog to what we mean. I suppose if some nascent key were turned in our minds, we could finally get into the sweet spot where it could all converge absolutely.
And maybe @AJL's first post gives a new insight here!
I think MIN and MAX as functions should be implemented like used in other languages and CLAMP, CLAMPS could solve the whole thing with 3 parameters and a quite nice descriptive name.
CLAMP is what I said a while back.
Avoiding the 3 operand issue, I suggested CLAMPU and CLAMPL to do the clamp as two consecutive operations. Just like Chip has been showing with his example. The more I think about it the more I like this to replace MIN/MAX as they are now.
BTW, x := 5 !> x !> 10 does not work. It peaks out at 5 even when x is, say 9, just as x := 5 <# x <# 10 does in Spin1.
Here you underline the problem. You know how the old opcode works, so you are not reading what the symbols say, but are skipping ahead to what you know they will do.
Sadly, very few new P2 users will know anything about the old opcodes/symbols, so they will read the literal NOT and GREATER.
x := 5 NOT GREATER than x NOT GREATER than 10 , bounds x within 5..10, and operand order matters.
The real problem here is that something like x := 5 !> x !> 10 is allowed to work in the first place. It's just too ambiguous for a user to figure out. Certainly if you come from somewhere else. For clamping a value there must be way better options around. Including a 'clamp(x,y)' function-style mechanism, as has been suggested. Crystal clear, unlike the mess above.
An alternative here for SPIN2 is to create a pair of ternary instructions and a single constant (NA).
CLAMP lower value upper
CLAMPS lower value upper
When the upper or lower limit is not being used it can be replaced with NA. When the byte code compiler encounters the NA it can omit that operation. If only two operands are supplied an error can be thrown to ensure the programmer's intent is captured.
If no assignment is made the clamped result is placed in value.
Yes, that works too, there was an example back on page 8 ( from code by Jason Dorie) that had the form of
LowerLimit (operatorX) Value (operatorY) UpperLimit
and that does have a natural order suited to quick glance reading to it.
an alternative form of
operator LowerLimit Value UpperLimit
also has the same easy to scan benefits, & the benefit of it needs one keyword to set a range, not two.
Keywords could be CLAMP/CLAMPS/CLAMPU, or RANGE/RANGES/RANGEU or SPAN/SPANS/SPANU
An alternative here for SPIN2 is to create a pair of ternary instructions and a single constant (NA).
Yes, I've seen some languages use NULL, to tell the compiler the programmer deliberately left that empty, and it is commonly used as a 'not initialized' value.
#LIMS y <= x <= # ' lower limit of x (signed) is y (if y > x, replace x)
#LIMS y <= x <= z ' limit x (signed) between y and z
#LIMS # <= x <= z ' upper limit of x (signed) is z (if x > z, replace x)
Easy to understand, and # is used when that limit is invalid/not-used.
Note I used #xxxx for the text operator to avoid using usable/valid labels/variables/constants.
This would all be so much easier if we just got rid of the notion of using operators and just replace them with intrinsic function calls, such as min(x,y), max(x,y) and limit(x,y,z). Spin already has intrinsic functions that map directly to byte codes, which are strsize and strcomp. Why not use intrinsic functions to replace <# and #>?
I would even argue that the ternary operator should be an intrinsic function call, such as lookup(x, y, z) instead of adopting the clumsy C "x?y:z" syntax. At the byte code level the generated code will look the same independent of whether an operator is used or an intrinsic function call is done. Which begs the question of why we are even discussing syntax right now since it doesn't matter at the byte code level. Isn't it more important to get the P2 into synthesis than it is to debate the syntax for <# ?
This would all be so much easier if we just got rid of the notion of using operators and just replace them with intrinsic function calls, such as min(x,y), max(x,y) and limit(x,y,z). Spin already has intrinsic functions that map directly to byte codes, which are strsize and strcomp. Why not use intrinsic functions to replace <# and #>?
This would all be so much easier if we just got rid of the notion of using operators and just replace them with intrinsic function calls, such as min(x,y), max(x,y) and limit(x,y,z). Spin already has intrinsic functions that map directly to byte codes, which are strsize and strcomp. Why not use intrinsic functions to replace <# and #>?
I would even argue that the ternary operator should be an intrinsic function call, such as lookup(x, y, z) instead of adopting the clumsy C "x?y:z" syntax. At the byte code level the generated code will look the same independent of whether an operator is used or an intrinsic function call is done. Which begs the question of why we are even discussing syntax right now since it doesn't matter at the byte code level. Isn't it more important to get the P2 into synthesis than it is to debate the syntax for <# ?
Agreed! I tried to make this argument earlier, but several people balked at it. Well, I did argue the extreme of having no operators at all, which might be pushing things a bit. But I still maintain that we should keep the operator syntax to a minimum. This argument over limit syntax would have been long over if they had just been made into functions to start with.
A related concern, which I mentioned earlier, is one of namespaces. No, I don't necessarily want to add namespaces. Just that intrinsic functions pollute the global namespace. This wasn't an issue for Spin on P1 because the language was basically static. However, I expect Spin 2 to grow over time. And that means you have a potential for breaking changes if new intrinsic functions are added. One approach to avoiding this is to introduce namespaces, but that brings its own baggage. Adding classes provides a limited namespace, but doesn't address global functions.
The alternative I was suggesting was to use two different syntaxes for intrinsic function calls and user function calls. That way, the compiler can differentiate names, new intrinsics can be added without fear of name collisions, and the code is self-documenting (you can easily see which functions are user-defined and which are not). As for the actual intrinsic-function syntax, I don't know what that should be.
Incidentally, in xBase languages, the ternary operator is "iif" (immediate if).
I confess that I've been lurking for a while and was essentially proposing a new perspective on other proposals.
These limit operations seem to be special cases of the ternary conditional assignment operation.
A #> B
' seems equivalent to
(A>B)?A:B
B <# C
' seems equivalent to
(B<C)?B:C
If intrinsic functions are used I'd suggest select(cond,x,y) rather than lookup(x,y,z), which conjures conflicting memories of Excel formulas, or iif (x,y,z), which doesn't seem education friendly; but limit(minimum, value, maximum) works just as well as clamp(minimum, value, maximum).
Operators are easier to type and easier for the eye to parse. Function calls are okay -- until they become nested. Then it's just a mess of parentheses that you have to unravel to figure out what's really happening. If everything were done with intrinsic function calls, what you would end up with is Forth with parentheses. So I would keep intrinsic function notation to an absolute minimum.
Operators are easier to type and easier for the eye to parse. Function calls are okay -- until they become nested. Then it's just a mess of parentheses that you have to unravel to figure out what's really happening. If everything were done with intrinsic function calls, what you would end up with is Forth with parentheses. So I would keep intrinsic function notation to an absolute minimum.
There's nothing wrong with x := x !< 5 !> 10.
-Phil
+ 1
It's as simple as reading a sentence once you have memorized a very small number of operators.
Functions are easier to type and easier on the eye to parse. Weird operator symbols are OK, until they become nested. Then it's just a mess of weird symbols that you have to unravel to figure out what's really happening. If everything were done with weird operator symbols, what you would end up with is something indistinguishable from the line noise you get when you have the wrong baud rate setting. As your example shows. So I would keep weird operator symbols to an absolute minimum.
Functions are easier to type and easier on the eye to parse. Weird operator symbols are OK, until they become nested. Then it's just a mess of weird symbols that you have to unravel to figure out what's really happening. If everything were done with weird operator symbols, what you would end up with is something indistinguishable from the line noise you get when you have the wrong baud rate setting. As your example shows. So I would keep weird operator symbols to an absolute minimum.
Sorry, could not resist.
Can't really argue with that, but nested functions are not much if any better than nested operators in that respect. In both cases it's up to the programmer to make the code as easy to read as possible.
Operators generally take up less screen space than functions so they can make code easier to read by having a larger portion of code on screen at one time, but I agree that minimizing the number of operators is a good idea.
Ask someone who hasn't followed this thread what "x := x !< 5 !> 10" means and I doubt that most people will understand it. Ask any programmer what limit(x, 5, 10) means, and they'll most likely give you the right answer. They'll also probably tell you that max(x,y) produces the maximum value of x and y, and min(x,y) produces the minimum value. The meaning of "x := x !< 5 !> 10" just isn't obvious.
Ask someone who hasn't followed this thread what "x := x !< 5 !> 10" means and I doubt that most people will understand it. Ask any programmer what limit(x, 5, 10) means, and they'll most likely give you the right answer. They'll also probably tell you that max(x,y) produces the maximum value of x and y, and min(x,y) produces the minimum value. The meaning of "x := x !< 5 !> 10" just isn't obvious.
Small actual project example of how quickly functional only gets ugly.
I've been doing some work that requires creating encapsulated postscript code. I wrote a quick postscript snippit processor in C# to help debug math operations. The first version created symbolic results using functional notation.
Here is a postscript function to compute acos(x)
/acos {dup dup mul 1 exch sub sqrt exch atan} def
Here is sample input to my snippit processor and resulting output:
Input
'x' dup dup mul 1 exch sub sqrt exch atan
Output
atan(sqrt(sub(1,mul(x,x))),x)
The output with functional notation is still not very clear. I made a modified version that uses infix notation for add, sub, mul, div.
Input
'x' dup dup mul 1 exch sub sqrt exch atan
Output
atan(sqrt(1-x*x),x)
That result is much easier for me to see what is being calculated.
I would like to see operations that commonly have infix notation stay with having infix notation in SPIN, operations that are not CRYSTAL CLEAR however I would like to see use functional notation.
I consider the !< and >! operations to be an example where I personally would prefer functional notation.
Problem solved. Infix operators can be used to define functions, but not the other way around, unless the language is extensible. So if you want a function, just write one.
One problem with intrinsic functions having two or more parameters is that you have to know in which order they occur, if the order matters. And the use of such a function in one's program does not provide any clues. If you write it yourself, it's there in your code as self-documentation.
I thought Chip already said Spin will use the !< and !> operators, and what we are helping him decide is what to call the PASM instructions.
I still think CLAMPU/CLAMPL are good, perhaps CLAMPLO/CLAMPHI are a bit better? Still under 8 characters, so it fits Chip's desire for fitting in a tab stop.
Small actual project example of how quickly functional only gets ugly.
I've been doing some work that requires creating encapsulated postscript code. I wrote a quick postscript snippit processor in C# to help debug math operations. The first version created symbolic results using functional notation.
Here is a postscript function to compute acos(x)
/acos {dup dup mul 1 exch sub sqrt exch atan} def
Here is sample input to my snippit processor and resulting output:
Input
'x' dup dup mul 1 exch sub sqrt exch atan
Output
atan(sqrt(sub(1,mul(x,x))),x)
The output with functional notation is still not very clear. I made a modified version that uses infix notation for add, sub, mul, div.
Input
'x' dup dup mul 1 exch sub sqrt exch atan
Output
atan(sqrt(1-x*x),x)
That result is much easier for me to see what is being calculated.
I would like to see operations that commonly have infix notation stay with having infix notation in SPIN, operations that are not CRYSTAL CLEAR however I would like to see use functional notation.
I consider the !< and >! operations to be an example where I personally would prefer functional notation.
C.W.
I don't think anyone is seriously suggesting that everything be moved to functions. The operators that are common across almost all languages can remain operators.
These clamping operators are trivial, but their implementation as operators, instead of as functions, offends people because of their past experience, always seeing these presented as functions. I think, anyway.
At this point, write it the way you want it. This isn't the same as getting input on the P2 instruction set. If someone doesn't like it, they can design their own interpreter!
These clamping operators are trivial, but their implementation as operators, instead of as functions, offends people because of their past experience, always seeing these presented as functions. I think, anyway.
I'm sure that's true. But I think it's important to distinguish clamping operations from the traditional MIN and MAX functions that people are used to. I still think it's possible to make a reasonable stab at an operator syntax for clamping (in addition to the single ops, !< and !>). How about this:
x := 0 -[ x ]- 10
The -/b] and [b- pair form a trinary operator, and they look like clamps. Yes? No?
These clamping operators are trivial, but their implementation as operators, instead of as functions, offends people because of their past experience, always seeing these presented as functions. I think, anyway.
I'm sure that's true. But I think it's important to distinguish clamping operations from the traditional MIN and MAX functions that people are used to. I still think it's possible to make a reasonable stab at an operator syntax for clamping (in addition to the single ops, !< and !>). How about this:
x := 0 -[ x ]- 10
The -/b] and [b- pair form a trinary operator, and they look like clamps. Yes? No?
The usual min/max functions are reversed if you want to limit in a range.
They are okay to find the min or max, but not if you want to clip to min, max.
It's the opposite meaning, that's why you never find one set of operators, or function names for both cases.
And, back to REM vs. MOD, in Spin1 the // operator is a remainder; it's not the modulus. If MOD in Spin2 behaves the same way, we need a different mnemonic for it. Anyway, I don't know why we can't just keep //. But if we wanted to, we could add MOD to the mix, which treats the number as unsigned when doing the division.
I think // may have become the widespread comment to end of line?
The point about REM & MOD is valid, & many other languages confuse them somewhat, so support for bothREM and MOD is fine with me.
In current PASM, how would the code size compare ?
Comments
For sure in mathematics x = x+1 can not be correct. x can not be x and x-1 at the same time. This is only possible if there exists a previous x value, and a next x value and in between happens some procedurale processing. Either by a Spin code or by typing it in a calculator.
And it's the same with
5 < x < 10
in mathematics this shows the possible range of x, but in a programming language it's something different. It's a serie of procedurale steps that execute from left to right.
Andy
When the upper or lower limit is not being used it can be replaced with NA. When the byte code compiler encounters the NA it can omit that operation. If only two operands are supplied an error can be thrown to ensure the programmer's intent is captured.
If no assignment is made the clamped result is placed in value.
That would be an interesting use of an operator, having multiple arguments.
All these efforts are like feeling our way around an invisible shape, without quite the proper tools and approach to conform our thought with syntax, or finally penetrate the shape. Everything we manage to implement is only a half-baked analog to what we mean. I suppose if some nascent key were turned in our minds, we could finally get into the sweet spot where it could all converge absolutely.
I think MIN and MAX as functions should be implemented like used in other languages and CLAMP, CLAMPS could solve the whole thing with 3 parameters and a quite nice descriptive name.
And welcome to the forums AJL!
Enjoy!
Mike
Avoiding the 3 operand issue, I suggested CLAMPU and CLAMPL to do the clamp as two consecutive operations. Just like Chip has been showing with his example. The more I think about it the more I like this to replace MIN/MAX as they are now.
Yes, that works too, there was an example back on page 8 ( from code by Jason Dorie) that had the form of and that does have a natural order suited to quick glance reading to it.
an alternative form of
also has the same easy to scan benefits, & the benefit of it needs one keyword to set a range, not two.
Keywords could be CLAMP/CLAMPS/CLAMPU, or RANGE/RANGES/RANGEU or SPAN/SPANS/SPANU
Yes, I've seen some languages use NULL, to tell the compiler the programmer deliberately left that empty, and it is commonly used as a 'not initialized' value.
Note I used #xxxx for the text operator to avoid using usable/valid labels/variables/constants.
I would even argue that the ternary operator should be an intrinsic function call, such as lookup(x, y, z) instead of adopting the clumsy C "x?y:z" syntax. At the byte code level the generated code will look the same independent of whether an operator is used or an intrinsic function call is done. Which begs the question of why we are even discussing syntax right now since it doesn't matter at the byte code level. Isn't it more important to get the P2 into synthesis than it is to debate the syntax for <# ?
Agreed! I tried to make this argument earlier, but several people balked at it. Well, I did argue the extreme of having no operators at all, which might be pushing things a bit. But I still maintain that we should keep the operator syntax to a minimum. This argument over limit syntax would have been long over if they had just been made into functions to start with.
A related concern, which I mentioned earlier, is one of namespaces. No, I don't necessarily want to add namespaces. Just that intrinsic functions pollute the global namespace. This wasn't an issue for Spin on P1 because the language was basically static. However, I expect Spin 2 to grow over time. And that means you have a potential for breaking changes if new intrinsic functions are added. One approach to avoiding this is to introduce namespaces, but that brings its own baggage. Adding classes provides a limited namespace, but doesn't address global functions.
The alternative I was suggesting was to use two different syntaxes for intrinsic function calls and user function calls. That way, the compiler can differentiate names, new intrinsics can be added without fear of name collisions, and the code is self-documenting (you can easily see which functions are user-defined and which are not). As for the actual intrinsic-function syntax, I don't know what that should be.
Incidentally, in xBase languages, the ternary operator is "iif" (immediate if).
I confess that I've been lurking for a while and was essentially proposing a new perspective on other proposals.
These limit operations seem to be special cases of the ternary conditional assignment operation.
If intrinsic functions are used I'd suggest select(cond,x,y) rather than lookup(x,y,z), which conjures conflicting memories of Excel formulas, or iif (x,y,z), which doesn't seem education friendly; but limit(minimum, value, maximum) works just as well as clamp(minimum, value, maximum).
Regards,
Anthony.
There's nothing wrong with x := x !< 5 !> 10.
-Phil
+ 1
It's as simple as reading a sentence once you have memorized a very small number of operators.
Sorry, could not resist.
Can't really argue with that, but nested functions are not much if any better than nested operators in that respect. In both cases it's up to the programmer to make the code as easy to read as possible.
Operators generally take up less screen space than functions so they can make code easier to read by having a larger portion of code on screen at one time, but I agree that minimizing the number of operators is a good idea.
I've been doing some work that requires creating encapsulated postscript code. I wrote a quick postscript snippit processor in C# to help debug math operations. The first version created symbolic results using functional notation.
Here is a postscript function to compute acos(x)
/acos {dup dup mul 1 exch sub sqrt exch atan} def
Here is sample input to my snippit processor and resulting output:
Input
'x' dup dup mul 1 exch sub sqrt exch atan
Output
atan(sqrt(sub(1,mul(x,x))),x)
The output with functional notation is still not very clear. I made a modified version that uses infix notation for add, sub, mul, div.
Input
'x' dup dup mul 1 exch sub sqrt exch atan
Output
atan(sqrt(1-x*x),x)
That result is much easier for me to see what is being calculated.
I would like to see operations that commonly have infix notation stay with having infix notation in SPIN, operations that are not CRYSTAL CLEAR however I would like to see use functional notation.
I consider the !< and >! operations to be an example where I personally would prefer functional notation.
C.W.
Problem solved. Infix operators can be used to define functions, but not the other way around, unless the language is extensible. So if you want a function, just write one.
One problem with intrinsic functions having two or more parameters is that you have to know in which order they occur, if the order matters. And the use of such a function in one's program does not provide any clues. If you write it yourself, it's there in your code as self-documentation.
-Phil
I still think CLAMPU/CLAMPL are good, perhaps CLAMPLO/CLAMPHI are a bit better? Still under 8 characters, so it fits Chip's desire for fitting in a tab stop.
At this point, write it the way you want it. This isn't the same as getting input on the P2 instruction set. If someone doesn't like it, they can design their own interpreter!
The -/b] and [b- pair form a trinary operator, and they look like clamps. Yes? No?
-Phil
That's the clampiest idea, yet.
They are okay to find the min or max, but not if you want to clip to min, max.
It's the opposite meaning, that's why you never find one set of operators, or function names for both cases.
Andy
a benefit of this choice of glyph pairing, is it has no equivalent clear-but-wrong statement (unlike NOT, GREATER)
Above would be fine, with the aliases discussed before of
I think // may have become the widespread comment to end of line?
The point about REM & MOD is valid, & many other languages confuse them somewhat, so support for both REM and MOD is fine with me.
In current PASM, how would the code size compare ?