Skip to content

Sugestion: A way to declare Non Sparse Arrays #24752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
4 tasks done
emilioplatzer opened this issue Jun 7, 2018 · 8 comments
Closed
4 tasks done

Sugestion: A way to declare Non Sparse Arrays #24752

emilioplatzer opened this issue Jun 7, 2018 · 8 comments
Labels
Declined The issue was declined as something which matches the TypeScript vision

Comments

@emilioplatzer
Copy link

Search Terms

non sparse array.

(I read and understand (I supouse): #10272 #13778 )

Suggestion

Add a way to declare Non Sparse Arrays to take adventajes of type guards to have these adventajes:

  • detect trys of creating sparse arrays
  • no need to control if a poped or accessed elemet is not undefined

It could be something like: type a: NonSparse<ElementType[]> or type a:NonSparseArrayOf<ElementType>

Use Cases

Knowing and wanting that an array haves non undefined values.

Examples

    /////////// Actualy ///////////

    type Ene={n:string}
    var a:Ene[]=[{n:'uno'},{n:'dos'},{n:'tres'}];

    if(a.length){
        var e1 = a[a.length-1]; 
        var e2 = a.pop();  // e1 and e2 points to the same object
        console.log(e2.n); // [ts] Object is possibly 'undefined'.
        console.log(e1.n); // no error detects in e1 why?
    }

    /////////// SUGGESTION ///////////

    type Eme={n:string}
    var a:NonSparse<Eme[]>=[{n:'uno'},{n:'dos'},{n:'tres'}];

    if(a.length){
        var e1 = a[a.length-1]; 
        var e2 = a.pop();  // e1 and e2 points to the same object
        console.log(e2.n); // ok a is NonSparse
        console.log(e1.n); // ok a is NonSparse
        a.push({n:'tail'}); // ok
        a.unshift({n:'head'}); // ok
        a[a.length] = {n:'tail2'} // ok, same as push
        a[a.length+1] = {n:'far 1'} // ERROR, sparse
        a[7] = {n:'far 2'} // ERROR, may be sparse
        var i=8; 
        a[i] = {n:'far 3'} // ERROR, may be sparse
        if(i <= a.length){
            a[i] = {n:'far 2'} // ok, guard guarantees non sparse array
        }
        delete a[i]; // ERROR, me be transforming a into sparse array
        if(i >= a.length){
            delete a[i]; // ok, guard guarantees non sparse array
        }
    }

    /////////// CASE OF USE ///////////

    async function callSeq1(listOfFunctions:NonSparse<(()=>Promise<void>)[]>):Promise<void>{
        while(listOfFunctions.length){
            var f = listOfFunctions.pop();
            await f(); // [ts] Cannot invoke an object which is possibly 'undefined'.
        }
    }

    /////////// WORKARROUND ///////////

    async function callSeq2(listOfFunctions:NonSparse<(()=>Promise<void>)>[]):Promise<void>{
        var f;
        while(f = listOfFunctions.pop()){
            await f();
        }
    }

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. new expression-level syntax)
@RyanCavanaugh
Copy link
Member

I think the vast, vast majority of arrays are non-sparse; it seems like what you'd actually want is for the default Array behavior to be like this and need to opt in to sparseness.

@emilioplatzer
Copy link
Author

@RyanCavanaugh, I agree with you. But I think maybe changing that is a breaking change. Thats why I suggest a way to be more specific. A way to say "this array is non sparse".

That change would not bother me. But I do not know in which cases a breaking change is allowed.

@mhegazy mhegazy added the Declined The issue was declined as something which matches the TypeScript vision label Jul 18, 2018
@mhegazy
Copy link
Contributor

mhegazy commented Jul 18, 2018

The compiler today does not have any reasoning about array bounds. Its is not clear if there is a way to plug this into the current system.

@emilioplatzer
Copy link
Author

Do you want to label this issue to be a good idea for the future?

In special if you think that is need to enance array and tupple treatament.

For example:

        var e1 = a[a.length-1]; 
        var e2 = a.pop();  // e1 and e2 points to the same object

both points to the same object. e1 can be undefined in the same way that e2, but tsc does not warns any problem in e1.

Or in a tuple case:

   function a3(a:[T, T, T], b:T){
      a[7] = b; 
   }

the assigment inside the function does not warns the error. After that statement a not be a [T, T, T] tupple any more. It becames an simply sparse array.

I think than in the future there be the need of analyze all the array and tupples stuffs.

Please save this issue for that moment.

@mhegazy
Copy link
Contributor

mhegazy commented Jul 19, 2018

The issue will always be there. we do look at closed issues every now and then.
The thing is we are not anywhere close to be able to track this information in the type system today. It is possible that in a year or two things will be different and we would be able to get there. but i am sure things like #13778 will get us there first.

@emilioplatzer
Copy link
Author

I agree with you. Thank you

@emilioplatzer
Copy link
Author

I was playing with lib/lib.d.ts in interface Array<T> changing pop(): T | undefined and a I thought:

Perhaps the problem is not being able to specify the result type of the object to which a method has been applied.

For example:

var server = new Server();
await server.listen();
// ...
await server.close(); 

The variable server is of class Server but we can say that in the first time is of "type unstarted" then is of "type listening" and at the end of "type closed". Someone can says you are talking about state not type. May be right, but that state can be (in the future) checked at compile time with Typescript.

Then if we can do that, we can have betters arrays.

new Array<T>() =>  Array<T, 0>
var x:string[] = [] // x is of type Array<string,0>
x.push('hi')      // x is of type Array<string,1>

function chop<T, n>(a:Array<T,n>, e:T){
    if(a.length && a[0]==e){
        return a.shift();
    } 
}

var line = readline()
chop(x, line);   // after chop x is of type Array<string,1> | Array<string,0>

May be we can use a symbol ~> to anotate the out type.

chop: <T,n>(arr: Array<T,n> ~> Array<T,n|n-1>, element:T) => T | undefined;   // chop modifies arr
listen: () => Listener ~> ServerListening         // chop modifies this

It is too much? I am sorry

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Declined The issue was declined as something which matches the TypeScript vision
Projects
None yet
Development

No branches or pull requests

4 participants