On Sunday, 8 October 2023 at 06:02:14 UTC, Jonathan M Davis wrote:
The problem is that the compiler needs to be able to verify
that the types match, and when the return type of a function is
a dynamic array such as int[], it has no way of knowing how
many elements the array has and therefore can't verify at
compile time that the assignment will work. add a runtime check
to verify that the number of elements match, but that's not the
sort of thing that you typically do with a statically typed
language.
I agree.
And solutions like "algebraic types" used by typescript are not
applicable to D (You cant declare int|undefined)
```typescript
const sorted=<T>([first,...xs]:T[]):T[] => first===undefined ?
[] : [
...sorted(xs.filter(x=> x<=first )), first, ...sorted(
xs.filter(x=> x > first))
];
console.log( sorted([1,2,3,4,-1,-2,-3]) );
```
But it should with pattern matching
```D
auto sorted(T)(T[] entries) =>
match(entries) {
case [item, ...others] => ...
otherwise => []
}
```
Or with overloading (patter matching expressions on function
signature... similar to haskell)
```D
auto sorted(T)(T[] [item, ...others]) => ...;
auto sorted(T)(T[] []) => [];
```
Well, not really: because compiler can't predict witch "sorted"
version will be called on compile time. (May be it should be a
syntax suggar of an unique sorted method with match in the body)
However, while there are some benefits to being able to do
this, the response by many programmers from statically typed
languages is that it's cleaner to create a struct for this sort
of thing
I completly agree
, since then the values are contained together, and they have
names associated with them (since they'll be member variables
of the struct). So, while some programmers definitely want
tuple types to be built into D, a number of others don't like
the idea. As such, it's an open question whether we'll ever
have such tuples in D.
Destructuring is only a **Syntax sugar** applicable to well known
types (i.e. Structs). It is not related (exclusively) with
tuples:
The type of a function call (or a parameter) is perfectly known.
Typescript applies destructuring based on type matching (type
members names):
```typescript
type ICounter = {
inc: ()=>void
dec: ()=>void
value: ()=>number
}
function Counter(n:number=0):ICounter {
return {
inc: ()=>{ n++ };
dec: ()=>{ n-- }
value: ()=> n;
}
}
const {inc,value} = Counter();
inc();
inc();
console.assert( value() === 2 );
inc();
console.assert( value() === 3 );
```
It could be portable with Structs in D.
Personally, I found it is specially useful with parameters for
"dependencies injection":
```typescript
function CarsDAO( {db:{ withTransaction }, logger:{ info }}:
IContext ):ICarsDao {
return {
createCar,
updateCar
}
function createCar(data:CarDto):Promise<string> {
info("Lets create a car");
return withTransaction( trx=> trx.executeQuery("insert .....
returning key") );
}
}
const context:IContext = {
logger: Singleton(logger),
db: Singleton(Db),
carsDao: Singleton(CarsDao),
}
(async ({ carsDAO:{ createCar }, logger }:IContext)=>{
data:CarDTO = { registration: "ASD1232", model: "Citroën XS" };
const key = await createCar( data )
logger.info( `Car ${key} has been registered`);
})(context);
```
This kind of destructuring is semantically rich.
Note: The "hard" part for this kind of solutions (dependency
injection not based on classes) is the clousures management, and
D solves it magnificently...
Either way, the unpacking of dynamic arrays likely stands no
chance whatsoever of ever being added, > because it would
require runtime checks to determine whether the unpacking was
valid.
This is what pattern matching, some day, at runtime, should solve
:-)
-- Antonio