<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/compile-time-dependent-types-jdtiqkian" -->

---
title: Compile-Time Dependent Types | daily.dev
description: Syl is a new programming language that encodes compile-time computation in a modal type system, aiming to bring proper dependent types to systems programming....
canonical: https://daily.dev/posts/compile-time-dependent-types-jdtiqkian
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Compile-Time Dependent Types | daily.dev
og:description: Syl is a new programming language that encodes compile-time computation in a modal type system, aiming to bring proper dependent types to systems programming....
og:url: https://daily.dev/posts/compile-time-dependent-types-jdtiqkian
og:image: https://api.daily.dev/og/posts/JdTIQKIan.png
og:image:alt: Compile-Time Dependent Types
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Compile-Time Dependent Types

**[Hacker News](https://daily.dev/sources/hn)** · 15 min read · 0 upvotes · 0 comments

## Summary

Syl is a new programming language that encodes compile-time computation in a modal type system, aiming to bring proper dependent types to systems programming. It uses two mode axes, staticity and erasure, to track what's knowable at compile time versus runtime. Functions with static arguments get monomorphized, similar to C++ template specialization, while erased values never appear at runtime. Because Syl allows general recursion and type-in-type, it isn't suitable for theorem proving. Syl implements fuel limits so typechecking during development does not get stuck. Max Slater, the author, says the Syl compiler may be found on GitHub and the design still needs stories for mode polymorphism, lifetimes, linearity, and implicit parameters.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://thenumb.at/Syl-Intro>

## Questions this post answers

### What are the two mode axes in the Syl programming language's type system?

Syl has two mode axes: staticity and erasure. On staticity, a value is either static (knowable at compile time) or dynamic (may not be). On erasure, a value is either erased (may not be knowable at runtime) or unerased (knowable at runtime). Mode annotations can only weaken a mode, not strengthen it, so a static value can be treated as dynamic but not vice versa.

_Exploring modal type systems like this is easier to track amid new PL research on daily.dev._

### How does Syl avoid needing a totality checker for dependent type theorem proving?

Syl supports general recursion in compile-time computations and gives 'type' the type 'type', which means constructing an expression of a type does not prove the corresponding proposition, unlike Lean, Rocq, or Agda. This makes typechecking undecidable and functions can diverge, but in return Syl avoids needing a totality checker or universe machinery, and implements fuel limits so typechecking doesn't hang indefinitely during development.

_Readers comparing dependently typed languages can follow these type theory trade-offs on daily.dev._

### How does Syl implement a length-indexed vector type without using a signed integer index?

Syl defines a custom Peano 'nat' type as a recursive variant with zero and succ cases, since Syl lacks tools for reasoning about signed, fixed-width integers. It then defines an 'add' function on nats and a 'vec' function indexed by an erased nat, producing an unboxed length-indexed list, with an 'append' function whose type proves the output length equals the sum of the input lengths via add(n, m).

_Developers studying dependently typed vector encodings can keep up with language design posts on daily.dev._

## Community take

How the wider developer community reacted, aggregated from 5 discussions and 41 comments across hackernews, lobsters (as of 2026-10-30).

**TL;DR:** Discussion is mostly a deep, technical dissection of Syl's staticity/erasure axes versus existing dependent-type and two-level type theory (2LTT/QTT) approaches, with several commenters finding the terminology confusing and debating whether the design is truly novel or well-motivated.

**Sentiment:** 20% positive · 65% mixed · 15% skeptical

**The case for**

- Some find the compile-time/runtime erasure approach conceptually interesting and see overlap with their own experimental language projects.
- A few see value in the goal of a flexible, Rust-like safe systems language with powerful comptime features.

**The pushback**

- Several argue the two-axis (static/erased) model may be unnecessary compared to a simpler ordered axis or existing QTT-style (0/1/w) multiplicity tracking in Idris.
- The claim that 'dynamic + erased has no overhead' is disputed, since Syl's static-only layout data would require extra overhead to support.
- Multiple commenters found the static/dynamic and 'typed at runtime' terminology confusing or inconsistent with common usage.
- Comparisons to Idris's QTT suggest Syl may require per-value specialization/monomorphization that QTT-based systems avoid, which is seen as a limitation.
- The claim that general recursion/type-in-type makes it unsuitable for theorem proving is challenged as only true under one proof paradigm (type inhabitation), not HOL-style approaches.

**By community**

- hackernews (mixed): Technical back-and-forth questioning whether Syl implements 'real' dependent types and whether dynamic+erased values could be supported without overhead, alongside a tangent on C VLAs and dependent-type theory basics.
- lobsters (mixed): Detailed, generally constructive technical scrutiny of the staticity/erasure terminology and its relationship to QTT and 2LTT, with some confusion but genuine engagement and even a related side project shared.

**Hottest debate:** Whether Syl's two-axis staticity/erasure model is justified or whether a simpler single ordered axis (or existing QTT-style multiplicity tracking) would suffice without the monomorphization overhead.

**Open questions**

- Why are staticity and erasure modeled as two separate axes rather than points on one ordered axis?
- How does Syl's two-level type theory approach relate to and compare against Idris's quantitative type theory for similar erasure goals?
- Could Syl support dynamic values within types under a 'dynamic modality' without full runtime overhead, as suggested but not fully worked out by the author?
- Does Syl's monomorphization-per-value approach scale as well as QTT-based erasure that avoids specialization?

**Highlights**

> Dynamic + erased values will be erased / irrelevant for runtime computation and may be unknown at comptime, e.g. a function that takes the length of a `Vec` type as another param:     foo : {0 n : Nat} -> Vect n Int -> Int Idris2's QTT models this with `0` / `1` / `w`: `n` is used 0 times at runtime and can be erased from the final program. Any usages of this within the runtime relevant parts of the program would be a compilation error, but usages within types are fine. We don't need to know the concrete value of `n` & we can erase all of the usages of it within those types. Syl doesn't look like it's capable of type checking that with a dynamic `n`. > Here, `erased` also implies `static`, so `f` will be specialized on `x`. The `if erased` expression accepts a `static erased` condition and is guaranteed to resolve at compile time. Therefore, the body of `f true` is simply `print_int 0`, and likewise for `f false`.   Like Zig it's doing monomorphization on the comptime params. `foo` above need not be specialized for every value of `n`. In Syl, every distinct value of `n` passed to `foo` would need a specialized program in the final compilation unit. iiuc, the "second level" of 2LTT allows for the representation of the specialized functions, while QTT wouldn't require this specialization or a second layer representation (and can track linearity).
> — [jado on lobsters · 4 points, 1 comments](https://lobste.rs/s/d09iy3/compile_time_dependent_types#c_eee01x)

> The definitions of the terms `static`/`dynamic` confused me in that do not describe what I would intuitively think they do: > A static value is knowable at compile time; a dynamic value may not be. Dynamic does *not* necessarily mean that a value may be known at runtime in a given context; it just means that it may not be known at compile time. A `dynamic` + `erased` value is one that may not be proven at compile time, but does not need to exist at runtime. I understand this to mean that the machine code that gets generated does not depend on the value, nor does the runtime code need to use said value. A use case I can think of would be a function that does something with the first element of a list. You may want to know that the length is non-zero and unsigned, but you do not care what it is other than that. This may force the caller to do something like this: ``` if x.len > 0      then do_something_with_the_first_element(x)     else do_something_else(x) ``` No computation is actually done at compile time, and `do_something_with_the_first_element` does not actually use `x.len` but I do need to know *something* about it. At least, that's my impression.
> — [interlandi on lobsters · 2 points](https://lobste.rs/s/d09iy3/compile_time_dependent_types#c_ddqhb7)

> > And there is no reason to limit oneself this way for performance, because again dynamic + erased has no overhead. Not entirely, since Syl uses static data to describe types' runtime layout. Allowing dynamic there would require overhead (e.g. a uniform representation). That said, there's not a good reason to prevent types from ever mentioning dynamic values. I didn't include it in the post as I haven't entirely thought it through, but with OxCaml-style modalities, you should be able to mention runtime data in types under a dynamic modality.
> — [TheNumbat on hackernews](https://news.ycombinator.com/item?id=50308210)

> I've experimented with simple designs in this space but not very recently. Anyway, regarding the theorem proving side of things that you lose because of... "Although this type system would not be suitable for a theorem proving language, it does not rule out type safety or even useful proofs. It has two practical consequences: - Functions used in type-level computations may diverge, so typechecking is not decidable. - Functions don’t discharge universally quantified claims, so the compiler must evaluate all applications that produce proofs before relying on their results." "Not suitable" seems to assume the type inhabitation approach to theorem proving, as in Rocq, Agda and Lean. But an alternative is some version of the HOL-family approach, as in HOL4, HOL Light and Isabelle/HOL. Then you can still use internal compile-time computation for proof automation. To be able to prove things about the code itself (and reflect it back to the compiler as trusted facts), you need a sound translation from code to logic or from logic to code. Code to logic is more ergonomic and therefore more attractive for the end-user, but it is trickier to get right with respect to soundness (which ties to the issue with divergence). Another way to put it is that if you have a sufficiently expressive compile-time system then you can build a bridge to an external proof system (exposed as a set of opaque LCF-style primitives) and still have internal proof automation, internal syntactic abstraction and all the rest, as opposed to having a jarring transition between the internal and external worlds. I haven't thought much about it in this context, so maybe you run into unresolvable issues. Hopefully experts can chime in.
> — [pervognsen on lobsters · 3 points](https://lobste.rs/s/d09iy3/compile_time_dependent_types#c_gngwli)

> Yeah I think this project could use a little guidance. The real magic with types parameters is that they can both be dynamic and erased! > That is, Syl is dependently typed at compile time and simply typed at runtime. This is not full dependent types. And there is no reason to limit oneself this way for performance, because again dynamic + erased has no overhead.
> — [Ericson2314 on hackernews · 1 comments](https://news.ycombinator.com/item?id=50306749)

**Source threads**

- [hackernews](https://news.ycombinator.com/item?id=50246538) · 54 points · 30 comments
- [hackernews](https://news.ycombinator.com/item?id=50265170) · 5 points · 0 comments
- [hackernews](https://news.ycombinator.com/item?id=50286542) · 1 points · 0 comments
- [hackernews](https://news.ycombinator.com/item?id=50283044) · 1 points · 0 comments
- [lobsters](https://lobste.rs/s/d09iy3/compile_time_dependent_types) · 30 points · 11 comments

## Similar posts on daily.dev

- [karans4/sysp: A systems Lisp that compiles to C. Homoiconic macros, refcounted memory, Hindley-Milner type inference.](https://daily.dev/posts/karans4-sysp-a-systems-lisp-that-compiles-to-c-homoiconic-macros-refcounted-memory-hindley-milne-mduxtkqjk) · Lobsters · 0 upvotes · 0 comments
- [Elixir v1.20 released: now a gradually typed language](https://daily.dev/posts/elixir-v1-20-released-now-a-gradually-typed-language-081x31cuq) · Elixir · 4 upvotes · 0 comments
- [Core Solidity Deep Dive](https://daily.dev/posts/core-solidity-deep-dive-yh5me5cu5) · Solidity · 3 upvotes · 1 comments
- [a perfectable programming language — Soter](https://daily.dev/posts/a-perfectable-programming-language-soter-kamjxh5mh) · Hacker News · 1 upvotes · 0 comments

---

Tags: [#type-systems](https://daily.dev/tags/type-systems), [#ocaml](https://daily.dev/tags/ocaml)

[View this post on daily.dev](https://daily.dev/posts/compile-time-dependent-types-jdtiqkian)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Compile-Time Dependent Types","url":"https://daily.dev/posts/compile-time-dependent-types-jdtiqkian","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/compile-time-dependent-types-jdtiqkian"},"datePublished":"2026-10-30T20:08:57.732Z","dateModified":"2026-10-30T20:09:40.059Z","description":"Syl is a new programming language that encodes compile-time computation in a modal type system, aiming to bring proper dependent types to systems programming....","image":"https://media.daily.dev/image/upload/s--OHB84bZF--/f_auto/v1722860399/public/Placeholder%2010","thumbnailUrl":"https://media.daily.dev/image/upload/s--OHB84bZF--/f_auto/v1722860399/public/Placeholder%2010","isAccessibleForFree":true,"articleSection":"Hacker News","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Hacker News","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/hn","url":"https://daily.dev/sources/hn"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/compile-time-dependent-types-jdtiqkian","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"type-systems,ocaml","timeRequired":"PT15M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Hacker News","item":"https://daily.dev/sources/hn"},{"@type":"ListItem","position":3,"name":"Compile-Time Dependent Types"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/compile-time-dependent-types-jdtiqkian#faq","mainEntity":[{"@type":"Question","name":"What are the two mode axes in the Syl programming language's type system?","acceptedAnswer":{"@type":"Answer","text":"Syl has two mode axes: staticity and erasure. On staticity, a value is either static (knowable at compile time) or dynamic (may not be). On erasure, a value is either erased (may not be knowable at runtime) or unerased (knowable at runtime). Mode annotations can only weaken a mode, not strengthen it, so a static value can be treated as dynamic but not vice versa. Exploring modal type systems like this is easier to track amid new PL research on daily.dev."}},{"@type":"Question","name":"How does Syl avoid needing a totality checker for dependent type theorem proving?","acceptedAnswer":{"@type":"Answer","text":"Syl supports general recursion in compile-time computations and gives 'type' the type 'type', which means constructing an expression of a type does not prove the corresponding proposition, unlike Lean, Rocq, or Agda. This makes typechecking undecidable and functions can diverge, but in return Syl avoids needing a totality checker or universe machinery, and implements fuel limits so typechecking doesn't hang indefinitely during development. Readers comparing dependently typed languages can follow these type theory trade-offs on daily.dev."}},{"@type":"Question","name":"How does Syl implement a length-indexed vector type without using a signed integer index?","acceptedAnswer":{"@type":"Answer","text":"Syl defines a custom Peano 'nat' type as a recursive variant with zero and succ cases, since Syl lacks tools for reasoning about signed, fixed-width integers. It then defines an 'add' function on nats and a 'vec' function indexed by an erased nat, producing an unboxed length-indexed list, with an 'append' function whose type proves the output length equals the sum of the input lengths via add(n, m). Developers studying dependently typed vector encodings can keep up with language design posts on daily.dev."}}]}
```

