Forums

Cobra design

General discussion about Cobra. Releases and general news will also be posted here.
Feel free to ask questions or just say "Hello".

Cobra design

Postby Dafra » Mon Feb 11, 2008 3:37 pm

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.

Quality
Great !

Contracts need a few samples (grepping the directory for require shows only comments :( ).
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. Furthemore, adding a random or to the second contract didn't help ; is this a bug ?

Defaulting numbers to Decimal
I 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 ?

The dot
Each call to a method needs to begin with a dot. What's the point ? (No pun intended).

Lowercase members : the Math.pI syndrom
It 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. :D
Dafra
 
Posts: 12

Re: Cobra design

Postby dennis » Mon Feb 11, 2008 10:52 pm

Dafra wrote:How to tell the compiler that 1.0 is a float ?


1.0f
dennis
 
Posts: 21

Re: Cobra design

Postby Charles » Mon Feb 11, 2008 11:13 pm

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:Quality
Great !

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 Decimal
I 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 syndrom
It 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. :D

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
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Cobra design

Postby Dafra » Tue Feb 12, 2008 2:16 pm

Chuck wrote:C# has #line, delegates, generics and reflection which all go a long way to making it a feasible as a backend.

I saw a temporary file appear and disappear during compilation. Isn't in memory compilation possible ?
Chuck wrote:BlindWatchMaker1 should be in your Samples directory and grep should hit it.

My fault : I grepped only HowTo.
Chuck wrote: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.

The message could be : The contract needs a "or require" clause.
The problem is that "or" (and "and ensure") seems to overlap completely with "is override". To be useful, it should be legal (and mandatory) only if an overriden method higher in the inheritance tree already has a "require" clause, informing the programmer that there is already a contract to take into account. Precondition inheritance is already there, so this shouldn't be too hard to implement.
Chuck wrote: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.

My favorite method for numerics, which doesn't work with all languages, is to alias the obvious choice at the beginning of the file.
alias float number
I declare all variables as "number", and later I can switch the alias to "double" or something else if needed. All you need is the ability to alias a type, which has other uses (e.g. to shorten a long type name). Implicit casting to higher precision types can help too.
As for the default type, sticking to CLI/C# standard will be the easiest for newcommers.
Dafra
 
Posts: 12

Re: Cobra design

Postby Charles » Thu Feb 14, 2008 2:26 am

Dafra wrote:I saw a temporary file appear and disappear during compilation. Isn't in memory compilation possible ?

Not in .NET 2.0. I haven't investigated newer versions to see if they addressed this. It is rather strange since there is a csc.dll that you can link to. But it still won't take a .NET string of C# source code to compile!

Dafra wrote:My fault : I grepped only HowTo.

But this reminds me that the HowTo needs a "contracts" entry that shows everything including "invariant" and "old". You mostly did the right thing, but of course you can leverage Samples too.

Dafra wrote:
Chuck wrote: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.

The message could be : The contract needs a "or require" clause.
The problem is that "or" (and "and ensure") seems to overlap completely with "is override". To be useful, it should be legal (and mandatory) only if an overriden method higher in the inheritance tree already has a "require" clause, informing the programmer that there is already a contract to take into account. Precondition inheritance is already there, so this shouldn't be too hard to implement.

No, I'm pretty sure that when you override a method without explicit contracts there is still an implicit "require true" and "ensure true" which might seem silly at first, but it goes back to this idea that an override can only "or" the requirements and "and" the ensures that it inherits. Otherwise if the overrider is saying "require .color <> Color.Black" instead of "or require .color...", it gives the impression that the overrider can really require that. But its super class has no requirement for that method so the subclass must respect that. It then appears that an overrider cannot provide useful requirements if its base method has none.

That's my understanding from reading up on Eiffel (but in my own words). Comments and feedback welcome.

Dafra wrote:
alias float number
I declare all variables as "number", and later I can switch the alias to "double" or something else if needed. All you need is the ability to alias a type, which has other uses (e.g. to shorten a long type name). Implicit casting to higher precision types can help too.


Cobra is likely to gain "subtypes" as in "type EvenNumber is int ..." followed by an optional "invariant" and methods and properties. However, as .NET does not allow truly subclassing various primitive types, it will be a Cobra-level illusion and the underlying type in the generated code will be "int" (or whatever) with a .NET attribute to indicate its type. So this aliasing thing might fold in with this, as in "type number is float".
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Cobra design

Postby Csaba » Thu Feb 14, 2008 2:51 pm

Hi Chuck,

A syntax change suggestion before it is to late:

From you example:

def main is shared
i = 1
for n in Fib.compute(10)
print '[i]. [n]'
i += 1

I much would prefer if instead of square braces [], “vertical line” | (0x7C) or broken bar | (0xA6) or both or some other less used character were used. The reason is that square braces are often written, but not the pipe symbol. Thereby it is easy to write:


def main is shared
i = 1
for n in Fib.compute(10)
print '[|i|] = [n]'
i += 1

to get [1] = 1


The example shows the same shortcoming that exists in VB, the iterator (as counter) is not available. A common suggestion in VB is that the iterator counter should be explicit.
A suggestion is in this example; the first is the iterator counter:

def main is shared

for i, n in Fib.compute(10)
print '[|i|] = [n]'


Of course, then comes teh discussion if the array is zero based or not etc……

Regards
Csaba
Csaba
 
Posts: 42

Re: Cobra design

Postby Dafra » Thu Feb 14, 2008 3:13 pm

Chuck wrote:
Dafra wrote:I saw a temporary file appear and disappear during compilation. Isn't in memory compilation possible ?

Not in .NET 2.0. I haven't investigated newer versions to see if they addressed this. It is rather strange since there is a csc.dll that you can link to. But it still won't take a .NET string of C# source code to compile!

Did you consider the CompileAssemblyFromSource method of CSharpCodeProvider ? Msdn2 says it compiles from a string. There is also an option to build the resulting assembly in memory, which will be quite useful when you write the CobraCodeProvider ;)

Chuck wrote:
Dafra wrote:The problem is that "or" (and "and ensure") seems to overlap completely with "is override". To be useful, it should be legal (and mandatory) only if an overriden method higher in the inheritance tree already has a "require" clause, informing the programmer that there is already a contract to take into account. Precondition inheritance is already there, so this shouldn't be too hard to implement.

No, I'm pretty sure that when you override a method without explicit contracts there is still an implicit "require true" and "ensure true" which might seem silly at first, but it goes back to this idea that an override can only "or" the requirements and "and" the ensures that it inherits. Otherwise if the overrider is saying "require .color <> Color.Black" instead of "or require .color...", it gives the impression that the overrider can really require that. But its super class has no requirement for that method so the subclass must respect that. It then appears that an overrider cannot provide useful requirements if its base method has none.
That's my understanding from reading up on Eiffel (but in my own words). Comments and feedback welcome.

A default "ensure true" is OK, but "require true" would kill all following preconditions since "true or something" is always "true". Default contracts should be viewed as empty lists of predicates.
Dafra
 
Posts: 12

Re: Cobra design

Postby Charles » Thu Feb 14, 2008 11:45 pm

Dafra wrote:
Chuck wrote:
Dafra wrote:I saw a temporary file appear and disappear during compilation. Isn't in memory compilation possible ?

Not in .NET 2.0. I haven't investigated newer versions to see if they addressed this. It is rather strange since there is a csc.dll that you can link to. But it still won't take a .NET string of C# source code to compile!

Did you consider the CompileAssemblyFromSource method of CSharpCodeProvider ? Msdn2 says it compiles from a string. There is also an option to build the resulting assembly in memory, which will be quite useful when you write the CobraCodeProvider ;)

I thought my research came up that this would just write a temporary file anyway. Maybe this is something you can look into when the source is opened this month. ;)

There is no CobraCodeProvider yet, but there is CobraCore.runCobraExe to help you out. It uses CobraCore.findCobraExe which you can invoke directly if you have some need to. See CobraLang.cobra in your bin directory for doc strings.

Dafra wrote:
Chuck wrote:
Dafra wrote:The problem is that "or" (and "and ensure") seems to overlap completely with "is override". To be useful, it should be legal (and mandatory) only if an overriden method higher in the inheritance tree already has a "require" clause, informing the programmer that there is already a contract to take into account. Precondition inheritance is already there, so this shouldn't be too hard to implement.

No, I'm pretty sure that when you override a method without explicit contracts there is still an implicit "require true" and "ensure true" which might seem silly at first, but it goes back to this idea that an override can only "or" the requirements and "and" the ensures that it inherits. Otherwise if the overrider is saying "require .color <> Color.Black" instead of "or require .color...", it gives the impression that the overrider can really require that. But its super class has no requirement for that method so the subclass must respect that. It then appears that an overrider cannot provide useful requirements if its base method has none.
That's my understanding from reading up on Eiffel (but in my own words). Comments and feedback welcome.

A default "ensure true" is OK, but "require true" would kill all following preconditions since "true or something" is always "true". Default contracts should be viewed as empty lists of predicates.


Well I think an empty list of requirements in a method kills all preconditions in overrides of that method. Say you have:
class ProviderA
def computeSomething as int
return 5

And then you use it like so:
class MyProgram

def doStuff(provider as ProviderA)
i = provider.computeSomething

I don't think you can (effectively) add requirements in an override of .computeSomething because users of ProviderA like the above MyProgram will be unexpectedly blocked from using the method. It's the same reason the requirements have to be ORed.
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Cobra design

Postby Dafra » Fri Feb 15, 2008 5:14 am

Chuck wrote:
Dafra wrote:A default "ensure true" is OK, but "require true" would kill all following preconditions since "true or something" is always "true". Default contracts should be viewed as empty lists of predicates.


Well I think an empty list of requirements in a method kills all preconditions in overrides of that method. Say you have:
class ProviderA
def computeSomething as int
return 5

And then you use it like so:
class MyProgram

def doStuff(provider as ProviderA)
i = provider.computeSomething

I don't think you can (effectively) add requirements in an override of .computeSomething because users of ProviderA like the above MyProgram will be unexpectedly blocked from using the method. It's the same reason the requirements have to be ORed.

You're right, empty list and true is the same, and I understand now why neither Eiffel nor D (nor Spec# ?) have a "or require".
Dafra
 
Posts: 12

Re: Cobra design

Postby Charles » Fri Feb 15, 2008 12:54 pm

Dafra wrote:You're right, empty list and true is the same, and I understand now why neither Eiffel nor D (nor Spec# ?) have a "or require".


I forget the D syntax, but Eiffel has "else require" and "then ensure". Cobra has the same thing but calls them "or require" and "and ensure" since the operations, as with Eiffel, are OR and AND.

The following search leads to a page on the topic, but then the Eiffel site reloads the browser with a generic frames based URL, hence the search:
http://www.google.com/search?hl=en&q=ei ... gle+Search
Charles
 
Posts: 2515
Location: Los Angeles, CA

Next

Return to Discussion

Who is online

Users browsing this forum: No registered users and 30 guests