Dafra wrote:Chuck, I have a few remarks and questions about the design of Cobra.
Spitting C# instead of IL
This works well for Eiffel compilers, and in benchmarks SmartEiffel often performs just as well as its backend gcc, so I hope this will work for Cobra too.
I'm sure it will now that I've been doing it for awhile. C# has #line, delegates, generics and reflection which all go a long way to making it a feasible as a backend. The worst case I've thought of is that sometimes it may be necessary to generate a private helper method which incurs a call overhead, but if Cobra is 90% as fast as C# and 90% as convenient as Python, I think we can be very happy.
Dafra wrote:QualityGreat !
Contracts need a few samples (grepping the directory for
require shows only comments
).
Not sure what's going on here.
BlindWatchMaker1 should be in your Samples directory and grep should hit it. There is a small
post on contracts if you haven't seen it already.
Dafra wrote:When I try this
class Divider
def inverse(x) as float
require
x > 3
body
return 1.0 / x
class Divider2
inherits Divider
def inverse(x) as float is override
require
x > 2
body
return 1.0 / x
I get a compiler error that says that the contract of
Divider2.inverse needs an
or. This is strange, because the compiler should
or the old contract with the new one, like Eiffel does. Furthermore, adding a random
or to the second contract didn't help ; is this a bug ?
Is the line number off? It should have been on the line with "require". In other words, the overriding method must say "or require". Eiffel has the same thing except I think they use a different word like "else". Maybe the error message needs to be improved.
So Cobra does OR them together like Eiffel. Since you mentioned that, you know the following, but for the benefit of other readers:
The point is that an overriding method can only weaken the contract by saying "or I'll do my work under these other conditions".
The issues with inheritance have to do with the fact that users of your code may only have a pointer to the base class and not have any knowledge of the subclass. Therefore, subclasses must respect the contracts they inherit. This is similar to how an overriding method must take the same number and types of arguments. If it took less or changed the types then it's not really an override.
Dafra wrote:Defaulting numbers to DecimalI don't like that, since all other languages use
int and
float instead.
In the code above, my first try with
inverse was
def inverse(x as float) as float
but the compiler rejected it because it mixes
float and
Decimal. How to tell the compiler that
1.0 is a
float ?
It's long overdue that computers compute the correct answers instead of the wrong. See the "Accurate Math" section of
Comparison to Python.
A: The "f" suffix as in "1.0f"
I do understand that this will be a pain for some. There are legit reasons to choose float over decimal, although accuracy and range are not among them. Speed and library constraints are.
So I'm playing with two ideas:
1. Make "fractional literals" such as "1.0" context sensitive. If implemented that would mean you would not have gotten an error because the float arguments set the context.
2. Make a "number" type and offer both a command line arg and an in-source compiler directive to set the type (float32, float64, decimal). This could even be something else in the future like a Rational which would have unlimited precision. Then you could easily try out the various fractional types and see how they impact your code. Of course, this number setting would change the default interpretation of literals to match the number type.
Comments are welcome. There are already 3 legit choices for fractional type and there will probably be 4 at some point. I feel strongly that something more needs to be done than just favoring one type.
Dafra wrote:The dot
Each call to a method needs to begin with a dot. What's the point ? (No pun intended).
Three points:
- Design point: When you access an object you say "obj.foo" so when you access the current object you say "this.foo". But as a shortcut you can skip "this". The dot remains to indicate the access.
- Readability point: When you glance at Cobra code, you can immediately distinguish between Types, .members and args/locals.
- Finally--and I'm really looking forward to this--when we have IDE support, typing ".st" is going to pop up Intellisense with all members starting with "st" and none of the types (String, StringBuilder, StringWriter, etc.) and that will be correct because you wouldn't have typed "." unless you were accessing a member. Or if you type "Stri" you'll get those three classes. C# Intellisense is always throwing things at me I knew I didn't need.
Dafra wrote:Lowercase members : the Math.pI syndromIt is a pity that Microsoft doesn't use casing to distinguish classes from members, but going against it is looking for trouble.
Won't it be a problem when using classes written in C# with lowercase members ?
Tools wil have a harder job : Intellisense will have to convert names of frameworks to Cobra format, and vice versa for online help systems.
We must also assume that no (braindead) programmer will ever design a class with 2 members differing only by casing.
Looks like trouble, but looks can be deceiving. While the "Math.pI incident" is unfortunate, it's easy enough to fix and therefore temporary. To have Intellisense convert to Cobra case conventions is very easy and language plugins have to provide their own Intellsense logic anyway.
Also, to ensure that Cobra can vend class libraries out to C# and VB, developers, it capitalizes the methods under the hood. There are other supporting features in this area like embedding the Cobra run-time. So C# developers can consume your DLL and feel comfortable doing so.
Re: two methods differing only by case, CLS forbids it and so you won't find it anywhere in the .NET base class library. You probably won't find it in any commercial libs and you could probably convince a third party to change their evil ways. If push comes to shove, there is always System.Reflection. I predict you'll need it for that purpose less than once in 10,000 lines of code.
-Chuck