<p>Making them a &quot;first-class value&quot; means that instances of them can be returned from functions, passed into functions, or constructed at runtime, which I'd presume is useful. But, I would also presume that it has somewhat of a performance overhead. So, what are the other advantages and disadvantages of making types as a first class value?</p>
<p><em>Credit to <a href="https://area51.stackexchange.com/users/223126/fess">fess</a> for the <a href="https://area51.stackexchange.com/proposals/127456/programming-language-design-and-implementation/127493#127493">similar idea on Area 51</a>.</em></p>

<types><first-class-objects>
What are the advantages and disadvantages of making types as a first class value?
CC BY-SA 4.0
2023-07-05T11:35:03.557Z
Why a performance overhead? If you don't use the feature in your program then it shouldn't affect your program's performance. If you do then it's not an overhead, just a normal cost.
kaya3
CC BY-SA 4.0
2023-07-05T11:38:08.217Z
@kaya3-supportthestrike at least one kind of implied performance overhead would be if the introduction of this feature forces the language to switch from static to dynamic typing. (Although that is not necessarily the case, as the feature could be implemented exclusively in compile-time, like in Zig)
abel1502
CC BY-SA 4.0
2023-07-05T12:41:35.223Z
If a program uses first-class types, and first-class types have a performance cost, that performance cost is not unnecessary for that program.
kaya3
CC BY-SA 4.0
2023-07-05T12:42:17.910Z
But first class types aren't necessary always @kaya3-supportthestrike
Starship
CC BY-SA 4.0
2023-07-05T12:55:53.897Z
They are for programs that use them. Programs that don't use them don't have to pay a cost for them. It's only a penalty (or unnecessary cost) if the same thing can be done cheaper, otherwise it is just a cost.
kaya3
CC BY-SA 4.0
2023-07-05T13:50:59.997Z
More important than the performance overhead is the potentially complexity cost of including them (which I imagine will be much higher if you want to add them to an existing framework rather than considering it in the initial design).
Bruce Adams
CC BY-SA 4.0
2023-07-05T23:08:35.673Z
@kaya3-supportthestrike: There are languages which do not have syntax for types, yet are statically typed with decideable type inference. In those languages, the lack of first-class types is a performance concern; they can be erased during compilation! This isn't enough material for a new answer, though.
Corbin
CC BY-SA 4.0
2023-07-06T00:58:20.960Z
Could [Racket contracts](https://docs.racket-lang.org/reference/contracts.html) count for this? If so, there might be an interesting answer in there somewhere. I've only used them a little bit when I've written some PLT-Redex models myself, though.
David Young
CC BY-SA 4.0
2023-07-06T01:00:24.717Z
Also, I wonder if any [gradually typed language](https://wphomes.soic.indiana.edu/jsiek/what-is-gradual-typing/) would have something like this. I see that there's [a paper](https://dl.acm.org/doi/10.1145/2398857.2384674) about "first-class classes" in a gradually typed language. Sounds like it's related to [mix-ins](https://en.wikipedia.org/wiki/Mixin).
David Young
CC BY-SA 4.0
2023-07-06T01:25:04.683Z
Would a static, compile-time mechanism for passing types count for this question? If so, dependent types definitely have some pros & cons and some of those might be directly related to passing types around. Also, they wouldn't necessarily affect performance, since they can be erased sometimes. I don't think I'm the right person to write an answer about that, though.
David Young
CC BY-SA 4.0
2023-07-06T07:54:52.667Z
@DavidYoung I think you have material there for a new answer. Are racket contracts like refinement types?
Bruce Adams
<h2>DRY and Consistency</h2>
<p>You have a list of integers and want to box each into a vector. The simplest way to do it is via a map function:</p>
<pre class="lang-hs prettyprint-override"><code>let xs = [42, 1917, 1921]
    ys = map (λx. [x]) xs
    in
ys = [[42], [1917], [1921]]
</code></pre>
<p>Now you have a list of types and want to box each into a vector type. According to the DRY Principle, the code should be the same for there should not exist two different <code>map</code> functions that repeat themselves:</p>
<pre class="lang-hs prettyprint-override"><code>let xs = [Int, String, StateRef Natural1]
    ys = map (λa. Vector a) xs
    in
ys = [Vector Int, Vector String, Vector (StateRef Natural1)]
</code></pre>
<p>Now of course, many languages do not do that, and those indeed all violate DRY:</p>
<ul>
<li>They require duplicate semantics for values, types, value functions, and type functions, assuming those semantics actually are similar.</li>
<li>They duplicate syntax (<code>f(x)</code> vs <code>F[X]</code> vs <code>F&lt;X&gt;</code> vs <code>F!X</code>).</li>
</ul>
<p>Each time you write this kind of code:</p>
<pre class="lang-swift prettyprint-override"><code>generic&lt;a, b&gt;
func map(f: a -&gt; b, xs: []a) []b
{
    match xs {
        (x :: ys) -&gt; f x :: map f ys
        [] -&gt; []
    }
}

generic&lt;f: generic&lt;type&gt;, xs: typeseq&gt;
struct MapTypes
{
    static if xs.length = 0 {
        static const result = make_typeseq&lt;&gt;;
    }
    else {
        static const result = make_typeseq&lt;f&lt;xs.head&gt;, MapTypes&lt;f, xs.tail&gt;.result&gt;;
    }
}
</code></pre>
<p>the DRY God looks at you with a saddened expression on its face for it is disappointed.</p>
<p>And as noted, some languages even have totally different and unrelated semantics for types and values, to the point of having <em>colanguages</em> incompatible with each other inside of a single one.<br />
C++ is the perfect example of this: C++ actually has full-fledged dynamically-dispatched <a href="https://en.wikipedia.org/wiki/Multiple_dispatch" rel="nofollow noreferrer">multimethods</a>! It just is limited to templates accepting types and literal constants. Compared to this, C++ &quot;functions&quot; are second-class citizens.</p>
<pre class="lang-cxx prettyprint-override"><code>template&lt;int x&gt;
struct fac
{
    static size_t val = x * fac&lt;(x - 1)&gt;::val;
};
template&lt;&gt;
struct fac&lt;0&gt; //first-class multimethod!
{
    static size_t val = 1;
};
</code></pre>
<p>In fact C++ goes further by reinventing boolean logic (<code>std::true_type</code>, <code>std::false_type</code>) and arithmetic (<code>std::integral_constant</code> and friends) in its template colanguage (none of which are related to nor share semantics with <code>bool</code>, <code>int</code> etc... because).<br />
Until first-class and typechecked concepts were introduced, it was also impossible to statically type-check any of this.<br />
Realising this, next time someone asks you what category it falls in, you should <a href="https://aphyr.com/posts/342-typing-the-technical-interview" rel="nofollow noreferrer">smile kindly and say &quot;C++ is a dynamically-typed, interpreted language.&quot;</a></p>

CC BY-SA 4.0
2023-07-05T15:03:40.650Z
2023-07-06T18:00:18.223Z
2023-07-06T18:00:18.223Z
Longinus
<h2>Simple syntax for generics / template / comptime</h2>
<p>Having types as first class language construct permits a generic/templating syntax where generic parameters are common arguments:</p>
<pre><code>def List( T type )
{ }

var listCodes = new List( int );
var listNames = new List( str );
</code></pre>
<h2>Avoid (a lot) of reflection</h2>
<p>Types then can have properties and methods, and so facilitate a lot of reflexive computation:</p>
<pre><code>def List( T type , capacity T )
{ }

var list32 = new List( u32 , u32.MaxValue );
var list64 = new List( u64 );
</code></pre>
<h2>Types returning types</h2>
<p>Say, you want specialized variations of your types. Things like machine fast integers, floating point numbers that set flags instead of generating errors/NaNs, optionals, <code>Either&lt;T,Error&gt;</code>. These specialized types are very detailed but very expensive to write in normal use.</p>
<p>But with first class types, these specializations can be write in very concise form:</p>
<pre><code>def AddFast( u32.fast a , u32.fast b ) as u32.fast  { ... }
def Div( u32 a , u32 b ) as u32.flags { ... } // nothrow
def ParseJson() as JsonNode.opt  { ... } // nothrow
</code></pre>
<h2>Source only first class types</h2>
<p>Some languages have full instantiable types that require a bigger runtime and incur in some performance overhead (C#, Java). but is possible to have the same comfort with types existing only for templating or <code>comptime</code> evaluation (Zig, C++).</p>

CC BY-SA 4.0
2023-07-05T15:47:44.920Z
2023-07-07T15:13:41.457Z
2023-07-07T15:13:41.457Z
André L F S Bacci
<p>Being able to use types as run-time values enables some dynamic constructs, but the extension beyond static generic type parameters is not large. Being able to use dynamic values <em>as</em> types expands the world of what you can have types express, enforce, and do significantly. These are the most interesting extensions.</p>
<p><a href="https://mwh.nz/pubs/dls2019" rel="nofollow noreferrer">First-Class Dynamic Types</a> in the 2019 DLS was an exploration of this. We took a language with an existing dynamic pattern-matching system and allowed those patterns to be used as types: anywhere that a type annotation could be written, a pattern expression could be written instead. Whenever a value passed through one of these annotations the pattern would be applied, and a match failure would be a run-time type error. The ordinary types of the language produced patterns matching values of that type, so those slotted in as equals with the first-class types.</p>
<p>Just this addition enabled a number of case studies (given in more detail in Section 4 of the paper). In brief, they were:</p>
<ul>
<li>Structural type checking using reflection: this can be implemented entirely in user code, whether it matches the language's native type system or not</li>
<li><em>Nominal</em> type checking using object brands</li>
<li>Range or restricted subtypes:
<pre class="lang-none prettyprint-override"><code>class RangeType(min, max) {
    method match(obj) {
        def int = obj.asInteger
        if ((int &lt; min) || (int &gt; max)) {
            return failedMatch(obj)
        }
        successfulMatch(int)
    }
}
type Byte = Range(0, 255)
method printByte(b : Byte) { ... }
</code></pre>
These can abstract arbitrarily-complex validation logic out into reusable pieces, with syntactic support from the type annotations.</li>
<li>Argument-dependent patterns: matching happened in order left-to-right, so <code>method getItem(list, index : be &gt;= 0 &amp; be &lt;= list.size)</code> worked with a careful <code>be</code> object with suitable operator overloads.</li>
<li>Higher-order dependent types: for example, a library could define a Matrix type, and a method could define its input and output validation with enforced types
<pre class="lang-none prettyprint-override"><code>class myMatrix {
    method *(other : Matrix(self.width, Number)) -&gt; Matrix(self.height, other.width) { ... }
}
</code></pre>
</li>
<li>Coercion and clamping: as patterns had not just a success or failure, but an enclosed value, types could also coerce their input values into range. This is... not obviously a good thing, but there are cases you might want to opt in explictly to <code>var x : Stringify</code> or <code>rating : Clamped(0, 10)</code>.</li>
<li>Decorators on other types: these are in part the &quot;constructed at run time&quot; side of things, where a wrapper could enforce additional constraints on top of another first-class type simply by implementing a suitable <code>match</code> method on the object, or (to some extent) relax those constraints.</li>
<li>General pre- and post-conditions asserted as types: the dynamic assertion could be determined by information outside or even unrelated to the scrutinee value, only leveraging the enforcement point. This is not particularly desirable on the language-design level, where you would probably just include those as a feature.</li>
</ul>
<p>It's a working system and <a href="https://github.com/mwh/kernan" rel="nofollow noreferrer">you can actually try it if you like</a>, including (very slowly) <a href="https://homepages.ecs.vuw.ac.nz/%7Emwh/ddttt-jsil/entry/" rel="nofollow noreferrer">in your browser</a>, including small examples of several of these case studies. Any arbitrary computable property can be used as the basis of a type, not just the ones listed.</p>
<p>There are associated costs with all of this, including whatever the direct costs of the dynamic tests in use are but also second-order effects from losing the firm constraints on shape and type that static types, or ordinary types enforced dynamically, provide to the run-time system.</p>
<p>There's also a choice to make about just <em>when</em> to bind these type expressions. Our system used very late binding, evaluating the expressions fresh each time, enabling some extremely dynamic behaviour. Another is to evaluate them early, at object construction time, and cache the resulting types: this provides more consistency, but less dynamicity. If you want static checking to exist alongside, extreme dynamism may not be what you want, but there are some tradeoffs to consider.</p>
<p>Racket's run-time contracts system permits dynamic user-defined checking, including the sort of dynamic value replacement used in some of the examples above. These are strictly more powerful because of higher-order contracts, impersonators, and contract defining forms, and you might not consider all of them to be &quot;types&quot;, but all of these things exist on a continuum. These are described in Takikawa et al. <em><a href="https://dl.acm.org/doi/10.1145/2398857.2384674" rel="nofollow noreferrer">Gradual Typing for First-class Classes</a></em>, OOPSLA 2012. A number of functional languages support some of this range of run-time checks, using first-class function values for types without their necessarily being &quot;first class&quot; values in their capacity <em>as</em> types.</p>
<hr />
<p>First-Class Dynamic Types. Michael Homer, Timothy Jones, James Noble. Dynamic Language Symposium (DLS), 2019. <a href="https://doi.org/10.1145/3359619.3359740" rel="nofollow noreferrer">https://doi.org/10.1145/3359619.3359740</a></p>
<p>Gradual Typing for First-class Classes. Asumu Takikawa, T. Stephen Strickland, Christos Dimoulas, Sam Tobin-Hochstadt, and Matthias Felleisen. OOPSLA, 2012. <a href="https://doi.org/10.1145/2398857.2384674" rel="nofollow noreferrer">https://doi.org/10.1145/2398857.2384674</a></p>

CC BY-SA 4.0
2023-07-06T02:57:23.600Z
2023-07-06T02:57:23.600Z
Michael Homer
<p>I am no expert in the theory of programming languages, but I have been working on a programming language for many years, and have always wanted these features:</p>
<ul>
<li>Ability to do reflection (get the type of an object)</li>
<li>Iterate the &quot;properties/columns/fields&quot; of a type (if it's a so-called &quot;record type&quot;). This is useful for <strong>documentation</strong> (you take the AST basically of the type and can iterate the props, etc.). It is also interesting to just inspect the type properties for doing <strong>validation</strong> and other things at runtime. More reflection-oriented stuff.</li>
</ul>
<p>So I went about designing the language with the idea that you could do:</p>
<pre><code>obj.type.fields.forEach(field =&gt; log(field.name))

if (obj.type.name == 'user') log('is user')
// or better
if (obj.type == UserType) log('is user')
</code></pre>
<p>and stuff like that. That would make programming so much easier IMO.</p>
<p>But you could also use the &quot;types&quot; at compile time, to do typechecking and other things.</p>
<p>The problem I am currently facing with this approach is based on the fact that I am compiling my language to JavaScript (for the browser). There are over 1000 types (more like 5000 types) defined for the browser / JS, some with dozens of properties. Lets say each type is 300 bytes of code, that is 1.5 megabytes or so of <em>just types</em>! If I allowed <code>obj.type.fields.forEach</code> on any possible object, that would mean I have to include this 1.5mb of mostly useless code from a programming perspective, into the final build JS file. That is way over the ideal size limit of about 100kb, in this case like 15x the appropriate size. Of course you could minify and gzip, but the point is clear, it adds a lot of text to the final build.</p>
<p>So now I'm facing a dilemma (which I'd love to hear solutions for as well in the comments, if you have any suggestions, or maybe someday I'll <a href="https://langdev.stackexchange.com/questions/2121/how-to-avoid-output-build-bloat-when-wanting-to-access-type-metadata-information">ask a related question</a>). The dilemma is, do I have to go back and cut this feature out, and rethink a tone of core functionality. Or can I somehow include only a subset of the type definitions in the final build? By that I mean, if the <code>.fields</code> is never accessed, but <code>.type.name</code> is, then perhaps I can omit the fields from the build, but include just the type names. I have a feeling other languages face a similar challenge in some sense, but I'm not sure how they handle it.</p>
<p>Anyway, just wanted to answer that there is this problem if you make your types first-class values. Types add a not insignificant amount of code to your codebase, and having to include that in any final build might be problematic like I've shown. But perhaps there are workarounds?</p>

CC BY-SA 4.0
2023-07-06T18:58:54.223Z
2023-07-06T19:21:01.503Z
2023-07-06T19:21:01.503Z
Lance Pollard
<p>I think the way in which you represent types as values affects the kind of performance characteristics.  Here are a few:</p>
<h2>Types as guard predicates</h2>
<p>A type is usable as a function that is called to check that a value may be assigned to a cell that the type guards.</p>
<p>Some languages make these equivalent</p>
<pre><code>let guardedCell: SomeTypeExpression = initialValue();

// is equivalent to using temporaries to capture
// the peices and invoking the guard to check the value

let tGuard = SomeTypeExpression;
let tInit = initialValue();
if (!tGuard(tInit)) { panic(); }
let guardedCell = tInit;
</code></pre>
<p>Obviously, any dynamic type checking involves runtime overhead because of the function call.
Where you statically know the type, and you know that the assigned type is compatible you can erase the guard call.</p>
<p>Typically, when using types as guard functions, you do suffer some performance cost because it limits your ability to do <a href="https://en.wikipedia.org/wiki/Type_erasure" rel="noreferrer">type erasure</a>.  For example, to know whether an empty list is a <em>string list</em> or some other kind of list, you need to store the element type with the list.</p>
<p>Also, widespread use of expensive guards that can't be optimized out might make programs slow in practice.</p>
<p>Things can get a tad wacky when instead of just staying &quot;types are value predicates&quot; you also say &quot;value predicates can be put in type place.&quot;</p>
<p>JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance" rel="noreferrer">allows overriding <code>instanceof</code></a> to arbitrary method calls, so you could have arbitrarily complex guards at runtime like a <em>PrimeNumber</em> guard so if you go the types-as-guards route, it's worth considering how users might be surprised by expensive guards.</p>
<pre><code>// JavaScript
// This is expensive
let PrimeNumber = {
  [Symbol.hasInstance](x) {
    if (!Number.isSafeInteger(x) || x &lt; 0) {
      return false
    }
    console.log(`Pretending to do expensive operation on ${x}`);
    return x === 2 || x === 3 || x === 5 || x === 7;
  }
};
// But people reading the below might think it's cheap.
console.log(
  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  .filter((x) =&gt; x instanceof PrimeNumber)
);
</code></pre>
<h2>Types as factory functions</h2>
<p>Python treats type expressions as factories.  <code>string(my_int)</code> constructs a string from an int and <code>MyClass(*args)</code> allocates memory creates a new instance of the class.</p>
<p>This doesn't carry much of a performance penalty, and Python still gets type introspection via the <code>type</code> and <code>isinstance</code> functions.</p>
<h2>Types as reflective facilities</h2>
<p>Smalltalk reifies types as meta-classes and Java uses a similar trick with its <code>Class&lt;T&gt;</code> reification of types.</p>
<p>There are many benefits to separating reflection from the values.  <a href="https://en.wikipedia.org/wiki/Mirror_%28programming%29#Benefits" rel="noreferrer"><em>Mirrors</em></a> allow limiting or reinterpreting reflection.</p>
<p>Reflection via meta-values often requires storing type information with all values that could be reflected over which can increase the size of values.  It also complicates optimizations like erasing boundaries around single property structs (inline types).</p>
<p>Mirror approaches, where the types you want to reflect over is declared, might allow for better managing that overhead than where <code>TopType.doReflectiveStuff</code> can possibly reflect over any type but in practice only affects a few.</p>

CC BY-SA 4.0
2023-07-05T15:01:14.097Z
2023-07-05T15:45:15.050Z
2023-07-05T15:45:15.050Z
Mike Samuel
# What are the advantages and disadvantages of making types as a first class value?
Posted by: username_0 on 2023-07-05
Making them a "first-class value" means that instances of them can be returned from functions, passed into functions, or constructed at runtime, which I'd presume is useful. But, I would also presume that it has somewhat of a performance overhead. So, what are the other advantages and disadvantages of making types as a first class value?

*Credit to [fess](https://area51.stackexchange.com/users/223126/fess) for the [similar idea on Area 51](https://area51.stackexchange.com/proposals/127456/programming-language-design-and-implementation/127493#127493).*
**Tags:** types first-class-objects
> **Comments:**
> **username_1**: Why a performance overhead? If you don't use the feature in your program then it shouldn't affect your program's performance. If you do then it's not an overhead, just a normal cost.  
> **username_2**: @kaya3-supportthestrike at least one kind of implied performance overhead would be if the introduction of this feature forces the language to switch from static to dynamic typing. (Although that is not necessarily the case, as the feature could be implemented exclusively in compile-time, like in Zig)  
> **username_1**: If a program uses first-class types, and first-class types have a performance cost, that performance cost is not unnecessary for that program.  
> **username_0**: But first class types aren't necessary always @kaya3-supportthestrike  
> **username_1**: They are for programs that use them. Programs that don't use them don't have to pay a cost for them. It's only a penalty (or unnecessary cost) if the same thing can be done cheaper, otherwise it is just a cost.  
> **username_3**: More important than the performance overhead is the potentially complexity cost of including them (which I imagine will be much higher if you want to add them to an existing framework rather than considering it in the initial design).  
> **username_4**: @kaya3-supportthestrike: There are languages which do not have syntax for types, yet are statically typed with decideable type inference. In those languages, the lack of first-class types is a performance concern; they can be erased during compilation! This isn't enough material for a new answer, though.  
> **username_5**: Could [Racket contracts](https://docs.racket-lang.org/reference/contracts.html) count for this? If so, there might be an interesting answer in there somewhere. I've only used them a little bit when I've written some PLT-Redex models myself, though.  
> **username_5**: Also, I wonder if any [gradually typed language](https://wphomes.soic.indiana.edu/jsiek/what-is-gradual-typing/) would have something like this. I see that there's [a paper](https://dl.acm.org/doi/10.1145/2398857.2384674) about "first-class classes" in a gradually typed language. Sounds like it's related to [mix-ins](https://en.wikipedia.org/wiki/Mixin).  
> **username_5**: Would a static, compile-time mechanism for passing types count for this question? If so, dependent types definitely have some pros & cons and some of those might be directly related to passing types around. Also, they wouldn't necessarily affect performance, since they can be erased sometimes. I don't think I'm the right person to write an answer about that, though.  
> **username_3**: @DavidYoung I think you have material there for a new answer. Are racket contracts like refinement types?  
---
## 5 answers
### Answer by username_10 on 2023-07-05. Score: 10 | Accepted answer
I think the way in which you represent types as values affects the kind of performance characteristics.  Here are a few:
Types as guard predicates
A type is usable as a function that is called to check that a value may be assigned to a cell that the type guards.
Some languages make these equivalent
let guardedCell: SomeTypeExpression = initialValue();

// is equivalent to using temporaries to capture
// the peices and invoking the guard to check the value

let tGuard = SomeTypeExpression;
let tInit = initialValue();
if (!tGuard(tInit)) { panic(); }
let guardedCell = tInit;

Obviously, any dynamic type checking involves runtime overhead because of the function call.
Where you statically know the type, and you know that the assigned type is compatible you can erase the guard call.
Typically, when using types as guard functions, you do suffer some performance cost because it limits your ability to do type erasure.  For example, to know whether an empty list is a string list or some other kind of list, you need to store the element type with the list.
Also, widespread use of expensive guards that can't be optimized out might make programs slow in practice.
Things can get a tad wacky when instead of just staying "types are value predicates" you also say "value predicates can be put in type place."
JavaScript allows overriding instanceof to arbitrary method calls, so you could have arbitrarily complex guards at runtime like a PrimeNumber guard so if you go the types-as-guards route, it's worth considering how users might be surprised by expensive guards.
// JavaScript
// This is expensive
let PrimeNumber = {
  [Symbol.hasInstance](x) {
    if (!Number.isSafeInteger(x) || x < 0) {
      return false
    }
    console.log(`Pretending to do expensive operation on ${x}`);
    return x === 2 || x === 3 || x === 5 || x === 7;
  }
};
// But people reading the below might think it's cheap.
console.log(
  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  .filter((x) => x instanceof PrimeNumber)
);

Types as factory functions
Python treats type expressions as factories.  string(my_int) constructs a string from an int and MyClass(*args) allocates memory creates a new instance of the class.
This doesn't carry much of a performance penalty, and Python still gets type introspection via the type and isinstance functions.
Types as reflective facilities
Smalltalk reifies types as meta-classes and Java uses a similar trick with its Class reification of types.
There are many benefits to separating reflection from the values.  Mirrors allow limiting or reinterpreting reflection.
Reflection via meta-values often requires storing type information with all values that could be reflected over which can increase the size of values.  It also complicates optimizations like erasing boundaries around single property structs (inline types).
Mirror approaches, where the types you want to reflect over is declared, might allow for better managing that overhead than where TopType.doReflectiveStuff can possibly reflect over any type but in practice only affects a few.
---
### Answer by username_6 on 2023-07-05. Score: 7
DRY and Consistency
You have a list of integers and want to box each into a vector. The simplest way to do it is via a map function:
let xs = [42, 1917, 1921]
    ys = map (λx. [x]) xs
    in
ys = [[42], [1917], [1921]]

Now you have a list of types and want to box each into a vector type. According to the DRY Principle, the code should be the same for there should not exist two different map functions that repeat themselves:
let xs = [Int, String, StateRef Natural1]
    ys = map (λa. Vector a) xs
    in
ys = [Vector Int, Vector String, Vector (StateRef Natural1)]

Now of course, many languages do not do that, and those indeed all violate DRY:

They require duplicate semantics for values, types, value functions, and type functions, assuming those semantics actually are similar.
They duplicate syntax (f(x) vs F[X] vs F vs F!X).

Each time you write this kind of code:
generic
func map(f: a -> b, xs: []a) []b
{
    match xs {
        (x :: ys) -> f x :: map f ys
        [] -> []
    }
}

generic, xs: typeseq>
struct MapTypes
{
    static if xs.length = 0 {
        static const result = make_typeseq<>;
    }
    else {
        static const result = make_typeseq, MapTypes.result>;
    }
}

the DRY God looks at you with a saddened expression on its face for it is disappointed.
And as noted, some languages even have totally different and unrelated semantics for types and values, to the point of having colanguages incompatible with each other inside of a single one.
C++ is the perfect example of this: C++ actually has full-fledged dynamically-dispatched multimethods! It just is limited to templates accepting types and literal constants. Compared to this, C++ "functions" are second-class citizens.
template
struct fac
{
    static size_t val = x * fac<(x - 1)>::val;
};
template<>
struct fac<0> //first-class multimethod!
{
    static size_t val = 1;
};

In fact C++ goes further by reinventing boolean logic (std::true_type, std::false_type) and arithmetic (std::integral_constant and friends) in its template colanguage (none of which are related to nor share semantics with bool, int etc... because).
Until first-class and typechecked concepts were introduced, it was also impossible to statically type-check any of this.
Realising this, next time someone asks you what category it falls in, you should smile kindly and say "C++ is a dynamically-typed, interpreted language."
---
### Answer by username_7 on 2023-07-05. Score: 5
Simple syntax for generics / template / comptime
Having types as first class language construct permits a generic/templating syntax where generic parameters are common arguments:
def List( T type )
{ }

var listCodes = new List( int );
var listNames = new List( str );

Avoid (a lot) of reflection
Types then can have properties and methods, and so facilitate a lot of reflexive computation:
def List( T type , capacity T )
{ }

var list32 = new List( u32 , u32.MaxValue );
var list64 = new List( u64 );

Types returning types
Say, you want specialized variations of your types. Things like machine fast integers, floating point numbers that set flags instead of generating errors/NaNs, optionals, Either. These specialized types are very detailed but very expensive to write in normal use.
But with first class types, these specializations can be write in very concise form:
def AddFast( u32.fast a , u32.fast b ) as u32.fast  { ... }
def Div( u32 a , u32 b ) as u32.flags { ... } // nothrow
def ParseJson() as JsonNode.opt  { ... } // nothrow

Source only first class types
Some languages have full instantiable types that require a bigger runtime and incur in some performance overhead (C#, Java). but is possible to have the same comfort with types existing only for templating or comptime evaluation (Zig, C++).
---
### Answer by username_8 on 2023-07-06. Score: 3
Being able to use types as run-time values enables some dynamic constructs, but the extension beyond static generic type parameters is not large. Being able to use dynamic values as types expands the world of what you can have types express, enforce, and do significantly. These are the most interesting extensions.
First-Class Dynamic Types in the 2019 DLS was an exploration of this. We took a language with an existing dynamic pattern-matching system and allowed those patterns to be used as types: anywhere that a type annotation could be written, a pattern expression could be written instead. Whenever a value passed through one of these annotations the pattern would be applied, and a match failure would be a run-time type error. The ordinary types of the language produced patterns matching values of that type, so those slotted in as equals with the first-class types.
Just this addition enabled a number of case studies (given in more detail in Section 4 of the paper). In brief, they were:

Structural type checking using reflection: this can be implemented entirely in user code, whether it matches the language's native type system or not
Nominal type checking using object brands
Range or restricted subtypes:
class RangeType(min, max) {
    method match(obj) {
        def int = obj.asInteger
        if ((int < min) || (int > max)) {
            return failedMatch(obj)
        }
        successfulMatch(int)
    }
}
type Byte = Range(0, 255)
method printByte(b : Byte) { ... }

These can abstract arbitrarily-complex validation logic out into reusable pieces, with syntactic support from the type annotations.
Argument-dependent patterns: matching happened in order left-to-right, so method getItem(list, index : be >= 0 & be <= list.size) worked with a careful be object with suitable operator overloads.
Higher-order dependent types: for example, a library could define a Matrix type, and a method could define its input and output validation with enforced types
class myMatrix {
    method *(other : Matrix(self.width, Number)) -> Matrix(self.height, other.width) { ... }
}


Coercion and clamping: as patterns had not just a success or failure, but an enclosed value, types could also coerce their input values into range. This is... not obviously a good thing, but there are cases you might want to opt in explictly to var x : Stringify or rating : Clamped(0, 10).
Decorators on other types: these are in part the "constructed at run time" side of things, where a wrapper could enforce additional constraints on top of another first-class type simply by implementing a suitable match method on the object, or (to some extent) relax those constraints.
General pre- and post-conditions asserted as types: the dynamic assertion could be determined by information outside or even unrelated to the scrutinee value, only leveraging the enforcement point. This is not particularly desirable on the language-design level, where you would probably just include those as a feature.

It's a working system and you can actually try it if you like, including (very slowly) in your browser, including small examples of several of these case studies. Any arbitrary computable property can be used as the basis of a type, not just the ones listed.
There are associated costs with all of this, including whatever the direct costs of the dynamic tests in use are but also second-order effects from losing the firm constraints on shape and type that static types, or ordinary types enforced dynamically, provide to the run-time system.
There's also a choice to make about just when to bind these type expressions. Our system used very late binding, evaluating the expressions fresh each time, enabling some extremely dynamic behaviour. Another is to evaluate them early, at object construction time, and cache the resulting types: this provides more consistency, but less dynamicity. If you want static checking to exist alongside, extreme dynamism may not be what you want, but there are some tradeoffs to consider.
Racket's run-time contracts system permits dynamic user-defined checking, including the sort of dynamic value replacement used in some of the examples above. These are strictly more powerful because of higher-order contracts, impersonators, and contract defining forms, and you might not consider all of them to be "types", but all of these things exist on a continuum. These are described in Takikawa et al. Gradual Typing for First-class Classes, OOPSLA 2012. A number of functional languages support some of this range of run-time checks, using first-class function values for types without their necessarily being "first class" values in their capacity as types.

First-Class Dynamic Types. Michael Homer, Timothy Jones, James Noble. Dynamic Language Symposium (DLS), 2019. https://doi.org/10.1145/3359619.3359740
Gradual Typing for First-class Classes. Asumu Takikawa, T. Stephen Strickland, Christos Dimoulas, Sam Tobin-Hochstadt, and Matthias Felleisen. OOPSLA, 2012. https://doi.org/10.1145/2398857.2384674
---
### Answer by username_9 on 2023-07-06. Score: 2
I am no expert in the theory of programming languages, but I have been working on a programming language for many years, and have always wanted these features:

Ability to do reflection (get the type of an object)
Iterate the "properties/columns/fields" of a type (if it's a so-called "record type"). This is useful for documentation (you take the AST basically of the type and can iterate the props, etc.). It is also interesting to just inspect the type properties for doing validation and other things at runtime. More reflection-oriented stuff.

So I went about designing the language with the idea that you could do:
obj.type.fields.forEach(field => log(field.name))

if (obj.type.name == 'user') log('is user')
// or better
if (obj.type == UserType) log('is user')

and stuff like that. That would make programming so much easier IMO.
But you could also use the "types" at compile time, to do typechecking and other things.
The problem I am currently facing with this approach is based on the fact that I am compiling my language to JavaScript (for the browser). There are over 1000 types (more like 5000 types) defined for the browser / JS, some with dozens of properties. Lets say each type is 300 bytes of code, that is 1.5 megabytes or so of just types! If I allowed obj.type.fields.forEach on any possible object, that would mean I have to include this 1.5mb of mostly useless code from a programming perspective, into the final build JS file. That is way over the ideal size limit of about 100kb, in this case like 15x the appropriate size. Of course you could minify and gzip, but the point is clear, it adds a lot of text to the final build.
So now I'm facing a dilemma (which I'd love to hear solutions for as well in the comments, if you have any suggestions, or maybe someday I'll ask a related question). The dilemma is, do I have to go back and cut this feature out, and rethink a tone of core functionality. Or can I somehow include only a subset of the type definitions in the final build? By that I mean, if the .fields is never accessed, but .type.name is, then perhaps I can omit the fields from the build, but include just the type names. I have a feeling other languages face a similar challenge in some sense, but I'm not sure how they handle it.
Anyway, just wanted to answer that there is this problem if you make your types first-class values. Types add a not insignificant amount of code to your codebase, and having to include that in any final build might be problematic like I've shown. But perhaps there are workarounds?
---
