AdaCore / ada-spark-rfcs

Platform to submit RFCs for the Ada & SPARK languages
63 stars 28 forks source link

Conditional expression evaluation #60

Closed jquorning closed 3 years ago

jquorning commented 4 years ago

Proposal

Allow for conditional expression execution.

Examples

R := 1.0;
R := (A / B when B /= 0.0);
-- A / B is evaluated and put into R when B /= 0.0 to avoid division by zero.

R := (A / B
          when B /= 0.0
          else 1.0);
--  A / B is evaluated and put into R when B /= 0.0 to avoid division by zero. Otherwise 1.0 is put into R.

Rationale

This proposal may look like (if cond then expr1 else expr2) expression, but only then selected expressions is executed. The false branch is guaranteed to not being executed.

Implementation

Should be doable.

Alternative

R := (when B /= 0.0
           then A / B
           else 1.0);
--  As above but focus on condition.
stephe-ada-guru commented 4 years ago

Jesper Quorning notifications@github.com writes:

Proposal

Examples


R := 1.0;
R := (A / B when B /= 0.0);
-- A / B is evaluated and put into R when B /= 0.0 to avoid division by zero.

It would be helpful to add "else R is unchanged" here.

So this is equivalent to:

if B /= 0.0 then
    R := A / B;
else
   null;
end if;

The advantage of the new syntax is that it is an expression, not a statement.

Which leads to the general notion of a "null expression":

(if C then A else null)

when A is not an access type. The expression has no value when C is False.

This makes sense when it is the immediate value for an assignment statement, because the assignment can be skipped, but in other contexts it makes no sense:

function Foo (D : in Integer) is ...

Foo ((if C then A else null));

what value does D have in the call to Foo?

We could require a default value on the D parameter, so we can treat it similar to an assignment statement, but then we have:

Foo (5 + (if C then A else null));

etc.

We could raise Program_Error if a null value is used in this way. That doesn't seem worth it; in general, the user has to provide the proper response to C begin False (it can't just be ignored).

In Java, any object can be "null"; Kotlin (Google's Java variant) provides "safe" code sytnax for dealing with null values; this proposal is trying to move Ada in that direction.

-- -- Stephe

glacambre commented 4 years ago

This proposal may look like (if cond then expr1 else expr2) expression, but only then selected expressions is executed. The false branch is guaranteed to not being executed.

I don't understand this. Isn't this the behavior of if-expressions already? The following program only prints a single character:

with Ada.Text_IO; use Ada.Text_IO;

procedure P is
   function A return Boolean is
   begin
      Put_Line("A");
      return True;
   end;
   function B return Boolean is
   begin
      Put_Line("B");
      return False;
   end;

   C : Boolean := (if True then A else B);
begin
   null;
end;

The reference manual is also quite clear on this:

20/3 {AI05-0147-1} {AI05-0188-1} For the evaluation of an if_expression, the condition specified after if, and any conditions specified after elsif, are evaluated in succession (treating a final else as elsif True then), until one evaluates to True or all conditions are evaluated and yield False. If a condition evaluates to True, the associated dependent_expression is evaluated, converted to the type of the if_expression, and the resulting value is the value of the if_expression. Otherwise (when there is no else clause), the value of the if_expression is True.

raph-amiard commented 3 years ago

Hi @jquorning,

This looks like this is out of the scope of what we want to accomplish, and potentially error inducing because the semantics are not obvious. In addition, if-expression provide enough in that regard in our opinion, while having more regular and understandable semanttcs.

Kind regards