You should have read the previous thread about this topic first to understand this one.
Hi Mark, it's me again - here's just one quote:
1.: Implement this as plain and normal function. This would slow down the resulting applications a lot, since call's to this function would be very often and it would make no sense to perform a stack intensive function call just to find out the length of a string or array object. Then there is also a language syntactical problem: How should this function be declared? Which parameter should it accept - a string or an array? It should accept both, however, BlitzMax doesn't support function overloading, so that you couldn't implement it for both, strings and arrays.
2.: Implement it as builtin-function, which always needs brackets. This would be quite fast (compared with a normal function) and syntactical possible. However, it would confuse the programmer: How can you differ between a builtin-function (which is a kind of operator) and a normal function? It is important to always be aware of whether you're using an operator or a function, since they have many different properties and attributes assuming execution speed, stack and register usage, variable types (you can't store operators in variables, functions however, can be stored). The syntax used to execute this operator would be equivalent to the syntax used to call a function. This would cause confusion for the BlitzMax users, since they couldn't definitely decide whether they're using a builtin-function or a real function. It would also be a lack of consistency, since all other operators don't need brackets.
3.: Implement it as plain and normal operator - without brackets. This would be as fast as the second alternative, since it is an operator as well. It would also be syntactically correct, since BlitzMax already has unary operators (negation operator and New-operator) and you would implement it the same way as you did with the others (which would give the language more consistency). Then you have two alternatives regarding the precedence of that operator:
a.: Give it the same precedence as the New-operator. This would result in a higher precedence than the member access operator, which would cause the programmer to also put brackets around the operator's parameter when accessing the length of an array or string inside an object and would have the same disadvantages like the alternative number two: The BlitzMax user wouldn't be aware of whether using an operator or a function, which could result in strange compiling bugs.
b.: Give it the same precedence as the negation operator. Then it would have a lower precedence than the member access operator, but a higher precedence than the mathematical operators. The user could easily access the length of an array or string stored in an object (thanks to lower precedence than member access operator), then the user also could do some calculations with the resulting length (thanks to higher precedence than mathematical operators). So the language could become consistent, easy to use and easy to understand.
Which alternative did you choose? You chose number 3b, which was the best and easiest thing you could do. But what did you change between version 1.20 and 1.22? You just changed it to alternative number 3a, which is resulting in a strange mix: Len is now neither an operator with easy to use precedence (which all the other operators have) nor a builtin-function nor a real function. It is an operator with an unreasonable precedence, causing people to put brackets in their code and making them think it was a function, which needed brackets (if I just quote the topic title of a thread in the programming forum: "Len is now a FUNCTION and not an operator").
What we now have is inconsistency. Not just because the precedence makes people think it was a function, also because the current BlitzMax versions (1.22 and 1.24) don't fit to all previous versions - code which compiled fine with 1.20 and the versions before doesn't do so anymore in version 1.22 and 1.24: BlitzMax lost backward compatibilty. However, backward compatibility is important if you want to develop bigger projects in BlitzMax - just imagine you developed most of your code in version 1.20 and just waited with releasing because you hoped some little bugs will be fixed in version 1.22; now you notice, the code doesn't compile anymore with version 1.22, however, if you compile with version 1.20 you'll still have these bugs and the programme you developed doesn't work the way you want. However, BlitzMax could only become a famous language if there were some bigger, successfull and famous applications programmed in it. But how do you want to make people develop professional programmes in BlitzMax if you don't support downward compatibility? Just compare with Java: have you ever heard of an operator in Java which has changed it's precedence? I didn't - however, this happened in BlitzMax, which is not a good omen for the future of BlitzMax.
If you say: "Now I can't change it back, because I would hurt backward compatibilities again, so it has to stay like it is now in version 1.24." Just think: How would an expression look like which can compile in version 1.22 and 1.24 and which can't compile in version 1.20? It would need to use the member access operator on a result of the Len-operator; however, the Len-operator returns an integer, but the member access operator needs a module, scope, type or object as parameter. So you won't find any code which compiles with 1.22 and 1.24, but doesn't with 1.20. You could easily say, changing the precedence was a bug and you'll change it back to the correct precedence, which would be the easiest way to solve this problem, also since you wouldn't have to change the documentation ;-)
Hi Mark, it's me again - here's just one quote:
Built-in 'bracketless' functions like this are dumb and I shouldn't have put them in in the first place.
Are you sure about that? Just remember the time when you decided to implement this as operator. I think you had three alternatives:1.: Implement this as plain and normal function. This would slow down the resulting applications a lot, since call's to this function would be very often and it would make no sense to perform a stack intensive function call just to find out the length of a string or array object. Then there is also a language syntactical problem: How should this function be declared? Which parameter should it accept - a string or an array? It should accept both, however, BlitzMax doesn't support function overloading, so that you couldn't implement it for both, strings and arrays.
2.: Implement it as builtin-function, which always needs brackets. This would be quite fast (compared with a normal function) and syntactical possible. However, it would confuse the programmer: How can you differ between a builtin-function (which is a kind of operator) and a normal function? It is important to always be aware of whether you're using an operator or a function, since they have many different properties and attributes assuming execution speed, stack and register usage, variable types (you can't store operators in variables, functions however, can be stored). The syntax used to execute this operator would be equivalent to the syntax used to call a function. This would cause confusion for the BlitzMax users, since they couldn't definitely decide whether they're using a builtin-function or a real function. It would also be a lack of consistency, since all other operators don't need brackets.
3.: Implement it as plain and normal operator - without brackets. This would be as fast as the second alternative, since it is an operator as well. It would also be syntactically correct, since BlitzMax already has unary operators (negation operator and New-operator) and you would implement it the same way as you did with the others (which would give the language more consistency). Then you have two alternatives regarding the precedence of that operator:
a.: Give it the same precedence as the New-operator. This would result in a higher precedence than the member access operator, which would cause the programmer to also put brackets around the operator's parameter when accessing the length of an array or string inside an object and would have the same disadvantages like the alternative number two: The BlitzMax user wouldn't be aware of whether using an operator or a function, which could result in strange compiling bugs.
b.: Give it the same precedence as the negation operator. Then it would have a lower precedence than the member access operator, but a higher precedence than the mathematical operators. The user could easily access the length of an array or string stored in an object (thanks to lower precedence than member access operator), then the user also could do some calculations with the resulting length (thanks to higher precedence than mathematical operators). So the language could become consistent, easy to use and easy to understand.
Which alternative did you choose? You chose number 3b, which was the best and easiest thing you could do. But what did you change between version 1.20 and 1.22? You just changed it to alternative number 3a, which is resulting in a strange mix: Len is now neither an operator with easy to use precedence (which all the other operators have) nor a builtin-function nor a real function. It is an operator with an unreasonable precedence, causing people to put brackets in their code and making them think it was a function, which needed brackets (if I just quote the topic title of a thread in the programming forum: "Len is now a FUNCTION and not an operator").
What we now have is inconsistency. Not just because the precedence makes people think it was a function, also because the current BlitzMax versions (1.22 and 1.24) don't fit to all previous versions - code which compiled fine with 1.20 and the versions before doesn't do so anymore in version 1.22 and 1.24: BlitzMax lost backward compatibilty. However, backward compatibility is important if you want to develop bigger projects in BlitzMax - just imagine you developed most of your code in version 1.20 and just waited with releasing because you hoped some little bugs will be fixed in version 1.22; now you notice, the code doesn't compile anymore with version 1.22, however, if you compile with version 1.20 you'll still have these bugs and the programme you developed doesn't work the way you want. However, BlitzMax could only become a famous language if there were some bigger, successfull and famous applications programmed in it. But how do you want to make people develop professional programmes in BlitzMax if you don't support downward compatibility? Just compare with Java: have you ever heard of an operator in Java which has changed it's precedence? I didn't - however, this happened in BlitzMax, which is not a good omen for the future of BlitzMax.
If you say: "Now I can't change it back, because I would hurt backward compatibilities again, so it has to stay like it is now in version 1.24." Just think: How would an expression look like which can compile in version 1.22 and 1.24 and which can't compile in version 1.20? It would need to use the member access operator on a result of the Len-operator; however, the Len-operator returns an integer, but the member access operator needs a module, scope, type or object as parameter. So you won't find any code which compiles with 1.22 and 1.24, but doesn't with 1.20. You could easily say, changing the precedence was a bug and you'll change it back to the correct precedence, which would be the easiest way to solve this problem, also since you wouldn't have to change the documentation ;-)