May 03, 2012
Ada shares many purposes with D: correctness from the language design too, mostly imperative, native compilation, efficiency of the binary, closeness to the metal (even more, because not requiring a GC, it's probably usable in more situations), generic programming, OOP, strong static typing, and both languages share many small features (like array slicing syntax, and so on).

Coding in Ada is a bit boring, because you have to specify every small detail and to write a lot, but for certain programming tasks, like code that can't have too many bugs, it's maybe the best language. As Ada vendors say, if your life depends on a program, you often prefer that code to be written in good Ada instead of good C. Even if writing Ada is slower than writing C or C++, you save some time later debugging less. Today for certain tasks Haskell seems to produce reliable code, but it uses a GC and it's lazy, so it's quite less strict compared to Ada.

I've found another pack of slides about the Ada 2012 language:
http://www.slideshare.net/AdaCore/ada-2012

Come quotations and comments from/about the slides:

[page 3] >In High-Reliable Software, choice is usually being made between C C++ Java Ada<

Maybe someday D too will be among those.


[p.6] >Applying these skills to any programming language should be easy for any developer<

Good luck with programming in Haskell :-)


[p.7] >Is the language properly supported by tools?<

Right, some bugs are avoided thanks to the supporting tools too.


[p.8] >Can the language full development cycle (specification/code/verification)?<

I don't know, regarding D.


[p.15] >Put as much (formal) information as possible in the code<

This is quite important for a language that wants to enforce more correctness.


[p.17] >Values are checked at run-time (can be deactivated)<

This often saves the programmer ass.


[p.19] >Arrays can be indexed by any discrete types (integers, enumeration)<

This is quite handy for enums (and sometimes chars), and reliable. Currently in D if you define an array with enum index you get an associative array, that is wasteful in both memory and performance for most enums that have contiguous values (but I think maybe D implementations will be free to use a more efficient array here, because the interface of AAs is opaque).


[p.21]
> Three parameter modes : in (input), out (output) and in-out (input/output)
>
> procedure Do_Something
>   (P1 : in     Integer; --  P1 can’t be changed
>    P2 : out    Integer; --  No initial value on P2

In D P2 is initialized...


[p.21]
> The compiler decides if it has to be passed by reference of copy
> 
> procedure Do_Something
>   (P1 : in Huge_Structure) –-  Passed by reference if too big

D offers more low-level knowlege/control here, it doesn't decide to pass by value or reference, leaving the decision to the programmer, I prefer D here.
But in D code like this, where a large value is passed, I'd like the D compiler to give a warning (despite once in a while that's exactly what you want?):

alias int[1_000] TA;
void int(TA a) {}


[p.22]
> Generalized contracts are available through pre and post-conditions
> 
> procedure P (V : in out Integer)
>    with Pre  => V >= 10,
>         Post => V'Old /= V;

So there's the Old (prestate) too in the Ada2012 built-in contract programming.


[p.30]
> * Pointers are typed, associated with accessibility checks
> * Objects that can be pointed are explicitly identifed
> * Pointers constraints can be specified
> – Is null value expected?
> – Is the pointer constant?
> – Is the object pointed by the pointer constant?

Ada has severl kinds of pointers, according to how much freedom they have.


[p.36]
> Ada 2012 detects "obvious" aliasing problems
> 
> function Change (X, Y : in out Integer) return Integer is
>    begin
>       X := X * 2;
>       Y := Y * 4;
> 
>       return X + Y;
>    end;
> 
>    One, Two : Integer := 1;
> 
> begin
> 
>    Two := Change (One, One);
>    -- warning: writable actual for "X" overlaps with actual for "Y“
> 
>    Two := Change (One, Two) + Change (One, Two);
>    --  warning: result may differ if evaluated after other actual in expression

Are such warnings/tests useful in D too?
D compiles this with no warnings/errors:

int change(ref int x, ref int y) {
    x *= 2;
    y *= 4;
    return x + y;
}
void main() {
    int one = 1, two;
    two = change(one, one);
    two = change(one, two) + change(one, two);
}


[p.42]
> if C in 'a' | 'e' | 'i'
>       | 'o' | 'u' | 'y' then

Sometimes Ada2012 is succint too.


[p.43]
> Function implementation can be directly given at specification time if it represents only an "expression"
> 
> function Even (V : Integer) return Boolean
>    is (V mod 2 = 0);

It's related to:
http://d.puremagic.com/issues/show_bug.cgi?id=7176

Bye,
bearophile
May 03, 2012
On 05/03/12 16:04, bearophile wrote:
> [p.19] >Arrays can be indexed by any discrete types (integers, enumeration)<
> 
> This is quite handy for enums (and sometimes chars), and reliable. Currently in D if you define an array with enum index you get an associative array, that is wasteful in both memory and performance for most enums that have contiguous values (but I think maybe D implementations will be free to use a more efficient array here, because the interface of AAs is opaque).

It's a reasonable default; D will let you choose how it's done.

   struct EA(T,I) {
      enum size_t FIRST = I.min, N = I.max - FIRST + 1;
      T[N] a;
      auto opIndex(I i) { return a[i-FIRST]; }
      auto opIndexAssign(T v, I i) { return a[i-FIRST] = v; }
      // etc for any other useful operator
   }

   enum E { one=10, two, three }

   EA!(int, E) a;
   a[E.three] = 42;
   assert(a[E.three]==42);
   assert(a.sizeof==int.sizeof*3);

It doesn't get much more efficient than this; the compiler will take care of the rest, both the type checking and optimizing it all away.

Maybe something like this should be in the std lib, but i'm not sure if it's very useful in it's raw form, usually you'll want a custom version; it would be more suited for a mixin-template library.

artur
May 03, 2012
On Thursday, 3 May 2012 at 14:04:41 UTC, bearophile wrote:
> [p.21]
>> The compiler decides if it has to be passed by reference of copy
>> 
>> procedure Do_Something
>>  (P1 : in Huge_Structure) –-  Passed by reference if too big
>
> D offers more low-level knowlege/control here, it doesn't decide to pass by value or reference, leaving the decision to the programmer, I prefer D here.
> But in D code like this, where a large value is passed, I'd like the D compiler to give a warning (despite once in a while that's exactly what you want?):
>
> alias int[1_000] TA;
> void int(TA a) {}

I was surprised a little when compiler rejected `ref in`.
May 03, 2012
> Currently in D if you define an array with enum index you get an associative array, that is wasteful in both memory and performance for most enums that have contiguous values (but I think maybe D implementations will be free to use a more efficient array here, because the interface of AAs is opaque).

And there is this small problem too:
http://d.puremagic.com/issues/show_bug.cgi?id=6974

------------------------

Kagamin:

> I was surprised a little when compiler rejected `ref in`.

But this compiles:

alias int[1_000] TA;
void foo(const ref TA a) {}
void main() {}

Bye,
bearophile
May 03, 2012
On Thu, 03 May 2012 13:03:34 -0400, Kagamin <spam@here.lot> wrote:

> On Thursday, 3 May 2012 at 14:04:41 UTC, bearophile wrote:
>> [p.21]
>>> The compiler decides if it has to be passed by reference of copy
>>>  procedure Do_Something
>>>  (P1 : in Huge_Structure) –-  Passed by reference if too big
>>
>> D offers more low-level knowlege/control here, it doesn't decide to pass by value or reference, leaving the decision to the programmer, I prefer D here.
>> But in D code like this, where a large value is passed, I'd like the D compiler to give a warning (despite once in a while that's exactly what you want?):
>>
>> alias int[1_000] TA;
>> void int(TA a) {}
>
> I was surprised a little when compiler rejected `ref in`.

in is synonymous for "const scope".

Doing "const scope ref" yields:

"scope cannot be ref or out"

which makes sense.  Just use const instead.

-Steve
May 03, 2012
On 03-05-2012 19:36, Steven Schveighoffer wrote:
> On Thu, 03 May 2012 13:03:34 -0400, Kagamin <spam@here.lot> wrote:
>
>> On Thursday, 3 May 2012 at 14:04:41 UTC, bearophile wrote:
>>> [p.21]
>>>> The compiler decides if it has to be passed by reference of copy
>>>> procedure Do_Something
>>>> (P1 : in Huge_Structure) –- Passed by reference if too big
>>>
>>> D offers more low-level knowlege/control here, it doesn't decide to
>>> pass by value or reference, leaving the decision to the programmer, I
>>> prefer D here.
>>> But in D code like this, where a large value is passed, I'd like the
>>> D compiler to give a warning (despite once in a while that's exactly
>>> what you want?):
>>>
>>> alias int[1_000] TA;
>>> void int(TA a) {}
>>
>> I was surprised a little when compiler rejected `ref in`.
>
> in is synonymous for "const scope".
>
> Doing "const scope ref" yields:
>
> "scope cannot be ref or out"
>
> which makes sense. Just use const instead.
>
> -Steve

Doesn't make sense to me. It seems perfectly normal to do something like this:

void foo(ref in int i)
{
    i = 42; // we're setting i indirectly, and not leaking it
}

int i;
foo(i);

-- 
- Alex
May 03, 2012
On 03-05-2012 20:29, Alex Rønne Petersen wrote:
> On 03-05-2012 19:36, Steven Schveighoffer wrote:
>> On Thu, 03 May 2012 13:03:34 -0400, Kagamin <spam@here.lot> wrote:
>>
>>> On Thursday, 3 May 2012 at 14:04:41 UTC, bearophile wrote:
>>>> [p.21]
>>>>> The compiler decides if it has to be passed by reference of copy
>>>>> procedure Do_Something
>>>>> (P1 : in Huge_Structure) –- Passed by reference if too big
>>>>
>>>> D offers more low-level knowlege/control here, it doesn't decide to
>>>> pass by value or reference, leaving the decision to the programmer, I
>>>> prefer D here.
>>>> But in D code like this, where a large value is passed, I'd like the
>>>> D compiler to give a warning (despite once in a while that's exactly
>>>> what you want?):
>>>>
>>>> alias int[1_000] TA;
>>>> void int(TA a) {}
>>>
>>> I was surprised a little when compiler rejected `ref in`.
>>
>> in is synonymous for "const scope".
>>
>> Doing "const scope ref" yields:
>>
>> "scope cannot be ref or out"
>>
>> which makes sense. Just use const instead.
>>
>> -Steve
>
> Doesn't make sense to me. It seems perfectly normal to do something like
> this:
>
> void foo(ref in int i)
> {
> i = 42; // we're setting i indirectly, and not leaking it
> }
>
> int i;
> foo(i);
>

On second thought, the 'const' in the 'in' would probably make this nonsensical. Still, passing structs by ref is a case where 'ref in' makes sense (e.g. matrices).

-- 
- Alex
May 03, 2012
Am 03.05.2012 16:04, schrieb bearophile:
> Ada shares many purposes with D: correctness from the language design
> too, mostly imperative, native compilation, efficiency of the binary,
> closeness to the metal (even more, because not requiring a GC, it's
> probably usable in more situations), generic programming, OOP, strong
> static typing, and both languages share many small features (like array
> slicing syntax, and so on).
>
> Coding in Ada is a bit boring, because you have to specify every small
> detail and to write a lot, but for certain programming tasks, like code
> that can't have too many bugs, it's maybe the best language. As Ada
> vendors say, if your life depends on a program, you often prefer that
> code to be written in good Ada instead of good C. Even if writing Ada is
> slower than writing C or C++, you save some time later debugging less.
> Today for certain tasks Haskell seems to produce reliable code, but it
> uses a GC and it's lazy, so it's quite less strict compared to Ada.

I am quite found of Ada, even if it means writting a bit more than C or C++, IDEs can help here. When coding in Java or .NET, the IDE writes most of the stuff already for me.

The company developing the open source Ada compiler GNAT, had the main
talk in this years FOSDEM.

Ada still suffers from the expensive compilers it had on the early years, but thanks to the increase in security concern in software, actually it seems to be picking up users in Europe, for projects where human lifes are at risk.

But D would, of course, be an easier upgrade path for C or C++ developers.

--
Paulo

May 03, 2012
Paulo Pinto:

>but thanks to the increase in security concern in software, actually it seems to be picking up users in Europe, for projects where human lifes are at risk.<

Recently I am seeing a little grow of the interest in Ada. Maybe they have accepted that despite the flaws of Ada, it's the best tool for certain purposes. But more probably, several other more important factors are at play, probably political too.


>But D would, of course, be an easier upgrade path for C or C++ developers.<

In my opinion for a decent C or C++ programmer it's not too much hard to learn the Zen of Ada, they share similar roots (Ada is closer to Pascal, C++ closer to C, but the paradigms used are similar. Example: Ada templates require explicit instantiation, but learning this doesn't require a C++ programmer to change his/her/hir brain a lot).

D seems fit to write videogame engines, but despite D is safer than C and C++, for high integrity software, I think D will need an external tool that enforces very strict safe coding standards, because @safe can't be enough. Example: on default Ada all integral values don't overflow silently. Another example: there are strict and safe built-in ways to use multi-cores. Another example: kinds of pointers.

I have not used Ada a lot, but I like how you usually define (strong) types for most classes of variables, like for integral values, each with their range, if they are sub-ranges (subtypes) of other strong ranges, and so on.

A small example. If you have two matrices, where one contains (r,c) row-column pairs of indexes of the other matrix, it's easy to enforce the tuple items to be inside the number of rows or columns of the other matrix. If the second matrix has to contain only positive values, plus let's say the -3 -2 and -1 values to signal special cases, it's easy to define such integral type, and so on. And the compiler will verify things at compile-time where possible (example: If you write a literal of a string of enumerated chars, or the second matrix, it will verify at compile-time that the values of the literal are in the specified ranges), and insert out of range tests for run-time. Such range kinds and tests don't require advanced type system features to be implemented by the Ada compilers, but they are able to catch a lot of bugs early, that in C/C++/D bite you often. In most C++ code I've seen there is not even a bit of such strong static typing of the integral values. This makes the code harder to modify, and just "int" used for ten different purposes makes it easy to use an integral variable where a totally different one was needed, this turns the C++/D code into a "soup" that's buggy and harder to debug. I don't like the carefree attitude of C-style languages regarding strong typing of integral values. I have seen that computer language features 30+ years old are able to avoid most of such troubles.

In functional languages as Haskell and F# such work on indexes and ranged values and so on is much less needed, but in high-performance Ada/C/C++/Delphi/D coding, they are used quite often.

Bye,
bearophile
May 04, 2012
On Fri, May 04, 2012 at 01:49:32AM +0200, bearophile wrote: [...]
> I have not used Ada a lot, but I like how you usually define (strong) types for most classes of variables, like for integral values, each with their range, if they are sub-ranges (subtypes) of other strong ranges, and so on.
[...]

This makes me wonder if such a thing is implementable in D without sacrificing efficiency. Perhaps have a series of templated structs that wrap around an int, that keep track of the range? TDPL gives an example of an int wrapper that checks for overflow.  I think it might be possible to write an int wrapper, say RangedInt!(min,max) that enforces a certain value range.  Member functions can handle cross-range computations (e.g., RangedInt!(1,10) is assignable to RangedInt!(0,15) without any checks, but the converse assignment will have a check, either runtime or compile-time if possible, to ensure the assigned value is within range).

You can also version the thing to omit range checks in -release mode or have the user specify some version=... to omit range checks, if he wishes to have maximum efficiency after extensive testing to ensure range violations don't happen.


T

-- 
Frank disagreement binds closer than feigned agreement.
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home