Semantic differences in Algol and C in casting

377 views Asked by At

Suppose we have the following instructions in Algol 68 and C, respectively: ref int x := 5; and (int*) x = 5;. What are their semantic difference?, it's the same?, because I think that the second one says something like "x will point to a constant" (it can't be compiled) and the first one says "x will point to a memory cell that points to another memory cell that contains a constant, 5". Is it correct?, if not, can you explain it a bit and give some examples to understand this?

3

There are 3 answers

2
Jonathan Leffler On BEST ANSWER

I don't pretend to be an Algol 68 (or Algol 60) expert — I've never compiled a thing in either language.

However, Wikipedia on Algol 68 mode declarations says:

However, the declaration real x; is just syntactic sugar for ref real x = loc real;. That is, x is really the constant identifier for a reference to a newly generated local real variable.

Given that explanation, the question's Algol fragment:

ref int x := 5;

corresponds (more or less) to the C code:

int *x = malloc(sizeof(*x));
*x = 5;

putting aside issues of error checking and release of the allocated memory.

The question's C fragment:

(int *)x = 5;

is largely meaningless — the result of a cast is not a modifiable lvalue, and you can only assign to a modifiable lvalue. If rewritten as:

int x_data;
int *x = &x_data;
*(int *)x = 5;

then it becomes valid C, though the cast is wholly superfluous. It could also be written to use memory allocation, of course. In C, any use of x to access an integer value (as opposed to a pointer) requires dereferencing in C (*x or x[0]). By contrast, in Algol 68, there's no need to explicitly dereference the variable x.

Although the question mentions 'constant' a couple of times, I see nothing that implies constancy in the code. The value 5 is assigned to a variable in a location. The value stored in the location can be changed later by another assignment.

The question title asks about casting, but I see no evidence of a cast in the Algol code, and it is not clear why a cast is considered necessary in the C code.

0
AudioBubble On

Algol68 took a rigorous approach to the meaning of a 'name' (which is not the same thing as an 'identifier'). One visible result of that is that Algol68 tends to have one-more-ref in the type/mode of an object than do other languages.

Thus INT is the mode of a constant integer (which may not even need memory allocated at run time). REF INT is the mode of an "integer variable", and REF REF INT is the mode of a "reference to an integer variable".

 INT x = 42; 
 REF INT y = LOC INT := x; 
 REF REF INT z = LOC REF INT := y;

LOC is a 'local generator' that essentially just allocates stack space and returns its 'name' (aka address).

(Note that '=' establishes an equivalence, and ':=' is assigning a value)

A desired for familiar syntax meant that the two variable declarations can use abbreviated forms:

INT y := x;
REF INT z := y;

but the mode of y is still REF INT, etc. IMO, that abbreviation was a bad idea.

C equivalence:

 #define x 42
 int y = x;
 int* z = &y;
0
NevilleDNZ On

Algol 68 has many implicit coercions available depending on context (Strong, Firm, Meek, Weak & Soft Context): cf Wikipedia & Algol68's Coercion Hierarchy.

Algol68 can implicitly handle:

  1. widening of precision and dimension (Strong)
  2. uniting different types (Firm)
  3. targeted dereferencing (Both Meek and Weak)
  4. proceduring, deproceduring (Soft)

C casting has more restricted implicit casting:

  1. limited to implicit of 'widening' of precision and float to int in some cases only. Widening to arrays requires pointers and manual coding using the "&" operator.
  2. Unions must be manually coded/created.
  3. There is no dereferencing during casting (C forces the coder to explicitly work out how many times dereference a pointer using the "*" operator).
  4. procedure without arguments must be explicitly defined by name and called using the "()" operator.

Example code with output...

File: deref_and_cast.c

#include <stdio.h>
#include <stdlib.h>

main(){
  auto int*** crrri;
  crrri=(int***)malloc(sizeof(int**));
  *crrri=(int**)malloc(sizeof(int*));
  **crrri=(int*)malloc(sizeof(int));
  ***crrri=255; /* coder to explicitly work out how many times dereference */
  printf("%5.1f\n",(float)***crrri); /* Again deref is muilt-explicit */
}

Output:

255.0

File: coerce_and_cast.a68

#!/usr/bin/a68g --script #
# -*- coding: utf-8 -*- #

LOC REF REF REF INT crrri;
REF REF REF REF INT(crrri):=HEAP REF REF INT;
REF REF REF INT(crrri):=HEAP REF INT;
REF REF INT(crrri):=HEAP INT;
REF INT(crrri):=255; # targeted dereferencing (3x) depending on contect #
printf(($"example meek coercion:"g(-5,1)l$,REAL(crrri)));

Examples of Hierarchy of implicit coercions

PROC VOID raise exception = end; # Implicitly cast a "GO TO" to a PROC #

# Soft: deprocedure a PROC to a VALUE #
printf(($"Soft:"gl$,random)); # Implicit Coercion #
printf(($"Soft:"gl$,REAL(random))); # Explicitly cast/deprocedure #

# Weak: dereference pointer chain to a "name" (LHS in C lingo) #
COMPL compl:= 0;
re OF compl := crrri; # Implicit Coercion #
REF REAL(re OF compl) := crrri; # Explicitly cast/dereference #
printf(($"Weak:"g(-0,4)g(7,4)"i"l$,compl));

# Meek: dereference to a value #
printf(($"Meek:"gl$,sin(crrri))); # Implicit Coercion #
printf(($"Meek:"gl$,sin(REAL(crrri)))); # Explicitly cast/dereference #

# Firm: unite to a UNION #
MODE IRC=UNION(INT,REAL,COMPL);
OP SIN = (IRC z)IRC: (z|(INT i):sin(i),(REAL r):sin(r),(COMPL z):complex sin(z));
printf(($"Firm:"gl$,SIN 1)); # Implicit Coercion #
printf(($"Firm:"gl$,SIN IRC(1))); # Explicitly cast/unite #

# Strong: widen to higher precision OR to an array #
FLEX [0]BOOL bool array := BIN crrri; # Implicit Coercion #
bool array := []BOOL(BIN crrri); # Explicitly cast/widen #
printf(($"Strong:"$,$g$,bool array,$l$));

end: SKIP

Output:

example meek coercion:255.0
Soft:+2.11679610884246e  -1
Soft:+4.01945464342605e  -1
Weak:255.0000+0.0000i
Meek:-5.06391634924491e  -1
Meek:-5.06391634924491e  -1
Firm:+8.41470984807897e  -1
Firm:+8.41470984807897e  -1
Strong:FFFFFFFFFFFFFFFFFFFFFFFFTTTTTTTT