It's the normal syntax in Spin for float expressions:
x := f.FMUL(f.FADD(a, b), f.FADD(c, d))
Now we're talking about something that should really be fixed. Spin understands floating point constants and constant expressions, but it is totally ignorant about floating point variables. It would be great if a float attribute could be attached to variables so that the compiler could handle floating point expressions with variables also.
First, you're not a novice programmer. You have engrained preferences and expectations. You are used to operators, so anything else will just not be as comfortable for you.
Second, I don't have a problem with your example. I find that perfectly understandable. Start throwing some |< and ~~ in there and I suspect the functional equivalent will be easier to understand.
Third, It's all relative. At the one end, we have PASM, which is as simple as it can get, but also the most tedious to write. At the other end, you have well-established HLLs that fully abstract the hardware away, but allow you to write very concise code. Spin, in my opinion, falls in between. I'd even go so far as to say that it leans more towards the PASM end of the spectrum, by virtue of it being designed for direct interaction with a specific microcontroller (i.e. closer to the metal).
So, yes I think getting rid of operators is a reasonable idea. Since any number of syntaxes could target the same bytecode interpreter, how about create another language that looks like C/C++/etc and is chock full of operator shorthand. I suppose you could make the same argument about an all-function syntax, but that takes me back to my earlier point about the importance of the spin language being educational at it's roots.
First, you're not a novice programmer. You have engrained preferences and expectations.
You are used to operators, so anything else will just not be as comfortable for you.
What has programming experience got to do with this? Anyone who has lived long enough to make it to high school knows something of arithmetic. They know what is the meaning of "+", "-", "×", "÷", "(" and ")". It should be blindingly obvious what those operators mean in a programming language. Given the small understanding that until Unicode computers did not have symbols for multiplication and division, "*" and "/" are obvious substitutes are they not? Keyboards still don't have those symbols.
I would suggest that use of such obvious notation is one reason why high level languages were developed in the first place. So that arithmetic formula could be expressed in a natural human readable way, rather than the cryptic mnemonics of assembler.
Where this goes wrong is in the invention of all kind of other operator symbols that are not natural to anyone. As we see in Spin. Then I agree with you that things like MAX(), ABS(), ROTL() would be better than making up cryptic symbol combinations.
Where this goes wrong is in the invention of all kind of other operator symbols that are not natural to anyone. As we see in Spin. Then I agree with you that things like MAX(), ABS(), ROTL() would be better than making up cryptic symbol combinations.
I think most agree that clear function names trump cryptic symbol combinations.
The details on how this is done will be up to Chip, but he seems prepared to have the cleanup pass.
Your ROTL() may have been a typo ? - as the natural existing convention name candidate for that would be ROL()
What has programming experience got to do with this? Anyone who has lived long enough to make it to high school knows something of arithmetic. They know what is the meaning of "+", "-", "×", "÷", "(" and ")". It should be blindingly obvious what those operators mean in a programming language. Given the small understanding that until Unicode computers did not have symbols for multiplication and division, "*" and "/" are obvious substitutes are they not? Keyboards still don't have those symbols.
I would suggest that use of such obvious notation is one reason why high level languages were developed in the first place. So that arithmetic formula could be expressed in a natural human readable way, rather than the cryptic mnemonics of assembler.
Where this goes wrong is in the invention of all kind of other operator symbols that are not natural to anyone. As we see in Spin. Then I agree with you that things like MAX(), ABS(), ROTL() would be better than making up cryptic symbol combinations.
Agreed, although there are a few additions that would also work if they were used consistently across languages. For instance "&" for "and", "<<" for rotate left, ">>" for rotate right, etc.
I like the changes to eliminate some really common gaffes. I really don't like the longer function syntax and would prefer we do as few of those as makes sense. LOG and friends maybe.
I agree with potatohead. Keep the infix operators as-is. Function notation for infix operators not only adds to text bloat, but it makes the code less readable when you have to visually parse a bunch of nested parentheses.
Once you get into Spin, the infix operators become second-nature. The only thing I have to refer to constantly is the precedence table. And sometimes, when I'm in a hurry, I just say "screw it" and add parens, even if it turns out they're not necessary. (Actually, the precedence table is so deep -- and at odds in places with those of other languages -- that it helps to add parens, even when I know they're not necessary.)
The only thing I have to refer to constantly is the precedence table. And sometimes, when I'm in a hurry, I just say "screw it" and add parens, even if it turns out they're not necessary. (Actually, the precedence table is so deep -- and at odds in places with those of other languages -- that it helps to add parens, even when I know they're not necessary.)
True, that syntax is not normal but that is due to the limitations of the spin/pasm compiler. It is at least easily understandable.
It's comprehensible, but it's very difficult to see things at a glance.
I greatly prefer:
len = sqrt( (dx*dx) + (dy*dy) )
sum = x + y + z + w
over
len = F32.FSqr( F32.FAdd( F32.FMul(dx,dx), F32.FMul(dy,dy) ) )
sum = F32.FAdd( x, F32.FAdd( y, F32.FAdd(z,w) ) )
I wrote a compiler for the Elev8 FPU so I could write the former and have it generate the latter for me. It's too hard to maintain and iterate on the "function" style once it gets past a certain level of complexity.
True, that syntax is not normal but that is due to the limitations of the spin/pasm compiler. It is at least easily understandable.
It's comprehensible, but it's very difficult to see things at a glance.
I greatly prefer:
len = sqrt( (dx*dx) + (dy*dy) )
sum = x + y + z + w
over
len = F32.FSqr( F32.FAdd( F32.FMul(dx,dx), F32.FMul(dy,dy) ) )
sum = F32.FAdd( x, F32.FAdd( y, F32.FAdd(z,w) ) )
I wrote a compiler for the Elev8 FPU so I could write the former and have it generate the latter for me. It's too hard to maintain and iterate on the "function" style once it gets past a certain level of complexity.
Of course the former is preferable but the latter is what you have to work with if the only tools you have are the Propeller Tool and the F32 object.
For ease of adoption, the common operators are now the same as C and Verilog.
For all those persnickety operators in Spin, I've substituted keywords that are self-explanatory. I decided against the function() syntax for them, as this way provides a simple and self-consistent way of doing (even buried) assignments. And I used "\" as a variable postfix to reassign the variable after it's been read (i.e. "IF flag\0" reads "flag", but post-sets it to 0).
For some operators, aliases are available (! same as NOT, && same as AND, etc).
Here is what I've got:
Operator Term Usage Assign Usage Type Description
----------------------------------------------------------------------------------------------------------------
:= x := y x := y assign set x to y
++ (pre) ++x ++x var prefix pre-increment
-- (pre) --x --x var prefix pre-decrement
?? (pre) ??x ??x var prefix PRNG reverse, var must be long
++ (post) x++ x++ var postfix post-increment
-- (post) x-- x-- var postfix post-decrement
?? (post) x?? x?? var postfix PRNG forward, var must be long
~ (post) x~ x~ var postfix post-bitwise NOT
\ (post) x\y x\y var postfix post-set to y
!, NOT !x != x unary Boolean NOT (0 = -1, non-0 = 0)
~ ~x ~= x unary Bitwise NOT, 1's complement
- -x -= x unary Negation, 2's complement
ABS ABS x ABS= x unary Absolute value
ENCOD ENCOD x ENCOD= x unary Encode MSB, 31..0
DECOD DECOD x DECOD= x unary Decode, 1 shl (x & $1F)
SQRT SQRT x SQRT= x unary Square root
LOG2 LOG2 x LOG2= x unary Unsigned to logarithm-base2
EXP2 EXP2 x EXP2= x unary Logarithm-base2 to unsigned
&&, AND x && y x &&= y binary Boolean AND (x <> 0 AND y <> 0, returns 0 or -1)
||, OR x || y x ||= y binary Boolean OR (x <> 0 OR y <> 0, returns 0 or -1)
& x & y x &= y binary Bitwise AND
| x | y x |= y binary Bitwise OR
^, XOR x ^ y x ^= y binary Bitwise XOR
>>, SAR x >> y x >>= y binary Shift right, preserve sign
<<, SHL x << y x <<= y binary Shift left
SHR x SHR y x SHR= y binary Shift right, 0's into MSB's
ROR x ROR y x ROR= y binary Rotate right
ROL x ROL y x ROL= y binary Rotate left
REV x REV y x REV= y binary Reverse y LSBs of x and zero-extend
AT_LEAST x AT_LEAST y x AT_LEAST= y binary Ensure x => y
AT_MOST x AT_MOST y x AT_MOST= y binary Ensure x <= y
+ x + y x += y binary Add
- x - y x -= y binary Subtract
* x * y x *= y binary Multiply
/ x / y x /= y binary Divide, return quotient
%, MOD x % y x %= y binary Divide, return remainder
SCAL x SCAL y x SCAL= y binary Scale, unsigned (x * y) >> 32
FRAC x FRAC y x FRAC= y binary Fraction, unsigned {x, 32'b0}/y
SIGNX x SIGNX y x SIGNX= y binary Sign-extend from bit y
< x < y <n/a> equality Check less than, returns 0 or -1
=<, <= x <= y <n/a> equality Check equal or less than, returns 0 or -1
== x == y <n/a> equality Check equal, returns 0 or -1
<>, != x <> y <n/a> equality Check not equal, returns 0 or -1
=>, >= x => y <n/a> equality Check equal or greater than, returns 0 or -1
> x > y <n/a> equality Check greater than, returns 0 or -1
? : x ? y : z <n/a> ternary choose between y and z
Looks very good to me.
Minor comments :
Can you add MOD as an alias for % ? (brings that into line with AND.OR.XOR)
SHR is a little unclear, as you have separate lines for >> and SHR ?
Seems that needs a shift arithmetic right (SAR) to cover all the choices that were in Spin ?
(& maybe SAL, which I guess copies LSB, given SAR copies MSB ?)
Is LOG natural, or base 10 ? - This is the usual naming convention around logs :
LN Natural logarithm
LOG Logarithm base 10
EXP Natural exponential (e to the given power)
Looks very good to me.
Minor comments :
Can you add MOD as an alias for % ? (brings that into line with AND.OR.XOR)
SHR is a little unclear, as you have separate lines for >> and SHR ?
Seems that needs a shift arithmetic right (SAR) to cover all the choices that were in Spin ?
(& maybe SAL, which I guess copies LSB, given SAR copies MSB ?)
Is LOG natural, or base 10 ? - This is the usual naming convention around logs :
LN Natural logarithm
LOG Logarithm base 10
EXP Natural exponential (e to the given power)
SHR shifts 0's into the MSB's, whereas ">>" does an arithmetic shift, as one would expect from other languages.
LOG and EXP are base-2, what would you suggest? LOG2 and EXP2, maybe?
I don't know if there's any call for SAL in SPIN. Nice to have in assembler, though.
Comments
First, you're not a novice programmer. You have engrained preferences and expectations. You are used to operators, so anything else will just not be as comfortable for you.
Second, I don't have a problem with your example. I find that perfectly understandable. Start throwing some |< and ~~ in there and I suspect the functional equivalent will be easier to understand.
Third, It's all relative. At the one end, we have PASM, which is as simple as it can get, but also the most tedious to write. At the other end, you have well-established HLLs that fully abstract the hardware away, but allow you to write very concise code. Spin, in my opinion, falls in between. I'd even go so far as to say that it leans more towards the PASM end of the spectrum, by virtue of it being designed for direct interaction with a specific microcontroller (i.e. closer to the metal).
So, yes I think getting rid of operators is a reasonable idea. Since any number of syntaxes could target the same bytecode interpreter, how about create another language that looks like C/C++/etc and is chock full of operator shorthand. I suppose you could make the same argument about an all-function syntax, but that takes me back to my earlier point about the importance of the spin language being educational at it's roots.
It's the syntax, true, but it's not normal.
https://despair.com/products/tradition
I would suggest that use of such obvious notation is one reason why high level languages were developed in the first place. So that arithmetic formula could be expressed in a natural human readable way, rather than the cryptic mnemonics of assembler.
Where this goes wrong is in the invention of all kind of other operator symbols that are not natural to anyone. As we see in Spin. Then I agree with you that things like MAX(), ABS(), ROTL() would be better than making up cryptic symbol combinations.
(at least for the immediately preceding point)
The details on how this is done will be up to Chip, but he seems prepared to have the cleanup pass.
Your ROTL() may have been a typo ? - as the natural existing convention name candidate for that would be ROL()
Only because we speak English mind. For anyone else it's probably as cryptic as hell.
Can we have a ROFL() for when someone asks to Rotate Float Left ?
That's been there for a l-o-n-g time now...
Branch and Catch Fire
Great posters on that site, thanks for posting it.
True, that syntax is not normal but that is due to the limitations of the spin/pasm compiler. It is at least easily understandable.
Agreed, although there are a few additions that would also work if they were used consistently across languages. For instance "&" for "and", "<<" for rotate left, ">>" for rotate right, etc.
Once you get into Spin, the infix operators become second-nature. The only thing I have to refer to constantly is the precedence table. And sometimes, when I'm in a hurry, I just say "screw it" and add parens, even if it turns out they're not necessary. (Actually, the precedence table is so deep -- and at odds in places with those of other languages -- that it helps to add parens, even when I know they're not necessary.)
-Phil
Same.
It's comprehensible, but it's very difficult to see things at a glance.
I greatly prefer: over I wrote a compiler for the Elev8 FPU so I could write the former and have it generate the latter for me. It's too hard to maintain and iterate on the "function" style once it gets past a certain level of complexity.
Of course the former is preferable but the latter is what you have to work with if the only tools you have are the Propeller Tool and the F32 object.
Thanks for all your thoughts on these operators.
For ease of adoption, the common operators are now the same as C and Verilog.
For all those persnickety operators in Spin, I've substituted keywords that are self-explanatory. I decided against the function() syntax for them, as this way provides a simple and self-consistent way of doing (even buried) assignments. And I used "\" as a variable postfix to reassign the variable after it's been read (i.e. "IF flag\0" reads "flag", but post-sets it to 0).
For some operators, aliases are available (! same as NOT, && same as AND, etc).
Here is what I've got:
So, which would you keep, "AND" or "&&"?
I like the "post_set " operator too.
Minor comments :
Can you add MOD as an alias for % ? (brings that into line with AND.OR.XOR)
SHR is a little unclear, as you have separate lines for >> and SHR ?
Seems that needs a shift arithmetic right (SAR) to cover all the choices that were in Spin ?
(& maybe SAL, which I guess copies LSB, given SAR copies MSB ?)
Is LOG natural, or base 10 ? - This is the usual naming convention around logs :
LN Natural logarithm
LOG Logarithm base 10
EXP Natural exponential (e to the given power)
I think they're all useful, too.
I just added the PRNG prefix and postfix operators back in, using "??".
SHR shifts 0's into the MSB's, whereas ">>" does an arithmetic shift, as one would expect from other languages.
LOG and EXP are base-2, what would you suggest? LOG2 and EXP2, maybe?
I don't know if there's any call for SAL in SPIN. Nice to have in assembler, though.
I'll add MOD for %.
Good ideas!