question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Existential type?

See original GitHub issue

Here’s a case where I need a few existentials. It’s for a definition file, where I need to have parameters for Binding and Scheduler, but it doesn’t matter to me what they are. All I care about is that they’re internally correct (and any doesn’t cover this), and I’d rather not simulate it by making the constructor unnecessarily generic.

The alternative for me is to be able to declare additional constructor-specific type parameters that don’t carry to other methods, but existentials would make it easier.

export interface Scheduler<Frame, Idle> {
    nextFrame(func: () => any): Frame;
    cancelFrame(frame: Frame): void;
    nextIdle(func: () => any): Idle;
    cancelIdle(frame: Idle): void;
    nextTick(func: () => any): void;
}

export interface Binding<E> extends Component {
    binding: E;

    patchEnd?(): void;

    patchAdd?(
        prev: string | E | void,
        next: string | E | void,
        pos: number,
    ): void;

    patchRemove?(
        prev: string | E | void,
        next: string | E | void,
        pos: number
    ): void;

    patchChange?(
        oldPrev: string | E | void,
        newPrev: string | E | void,
        oldNext: string | E | void,
        newNext: string | E | void,
        oldPos: number,
        newPos: number
    ): void;
}

export class Subtree {
    constructor(
        onError?: (err: Error) => any,
        scheduler?: type<F, I> Scheduler<F, I>
    );

    // ...
}

export class Root extends Subtree {
    constructor(
        component: type<E> Binding<E>,
        onError?: (err: Error) => any,
        scheduler?: type<F, I> Scheduler<F, I>
    );

    // ...
}

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:77
  • Comments:68 (19 by maintainers)

github_iconTop GitHub Comments

21reactions
cwohlmancommented, Jul 17, 2020

Existential types would also be useful for arrays of generics.

Example:

type Job<T, R> = { isJob(param: unknown): param is T, run(param: T): R }
class JobsHandler {
  jobs: Job<unknown, unknown>[] = [] // This breaks because of the error listed below
  // jobs: Job<any, any>[] = [] // too loose
  // jobs: Job<T, R>[] = [] // with existential types
    runJob<T, R>(thing: T): R {
    const job = this.jobs.find(job => job.isJob(thing));
    if (!job) {
        throw new Error('No job')
    }
    return job.run(thing); // ts error here, even though thing is guaranteed to be T
  }
  addJob<T, R>(job: Job<T, R>) {
      this.jobs.push(job)
  }
}
6reactions
pelotomcommented, Oct 19, 2017

For anyone interested in using existential types right now via the negation of universal types, the type annotation burden of doing so has been greatly reduced thanks to recent type inference improvements.

type StackOps<S, A> = {
  init(): S
  push(s: S, x: A): void
  pop(s: S): A
  size(s: S): number
}
 
type Stack<A> = <R>(go: <S>(ops: StackOps<S, A>) => R) => R

const arrayStack = <A>(): Stack<A> =>
  go => go<A[]>({
    init: () => [],
    push: (s, x) => s.push(x),
    pop: s => {
      if (s.length) return s.pop()!
      else throw Error('empty stack!')
    },
    size: s => s.length,
  })

const doStackStuff = (stack: Stack<string>) =>
  stack(({ init, push, pop, size }) => {
    const s = init()
    push(s, 'hello')
    push(s, 'world')
    push(s, 'omg')
    pop(s)
    return size(s)
  })

expect(doStackStuff(arrayStack())).toBe(2)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Existential type - HaskellWiki
Use 'existential types' - an extension to Haskell that can be found in most compilers. ... where x, y, z can be from...
Read more >
What is an existential type? - Stack Overflow
Universal/abstract types and existential types are a duality of perspective between the consumer/client of an object/function and the producer/implementation of ...
Read more >
An Introduction to Existential Types | by Stephen Bly - Medium
Let's start with the what. Existential types allow us to create abstract data types: stacks, queues, maps, heaps, etc. More generally, they ...
Read more >
Existential types in Rust | varkor's blog
An “existential type”, or “existentially-quantified type”, is a type that intuitively represents “any type satisfying a given property”. In the ...
Read more >
existential type - Wiktionary
NounEdit · (programming, type systems) A type that hides the underlying concrete type(s). quotations ▽synonym △. Synonym: existential. 2002, Benjamin C. · Used ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found