<h2>Background</h2>
<p>Following a set of simple rules, I can determine the output type of any statement.
For example, adding two integers gives me an integer, <code>list.get()</code> gives me whatever type the list contains and so on.</p>
<p>A code block is just one statement containing any number of statements.
Its output type is defined as the output type of the last statement:</p>
<pre><code>// s will be a string (&quot;20&quot;)
s = {
    a = 10
    to_string(a * 2)
}
</code></pre>
<p>This way, function return types are also determined just from the code written in that function (they don't need to be specified), but there are cases (more complicated functions etc) where you want to be sure you can't accidentally return a wrong type and mess up the function signature - it would be nice to specify the return type you <em>want</em> and know that this will be enforced.</p>
<h2>Issues with conventional syntax</h2>
<p>I could simply add the option to specify function return types, but I have already found situations where I wanted to annotate variables with their types, too.
So instead of adding multiple syntactical ways of forcing specific types, I would prefer having <strong>only one way</strong> to specify the return type that works for every situation - for example after the statement in question:</p>
<pre><code>// returns an int
x = 10
// same here
x = { 10 }
// same here, but the compiler enforces it
x = { 10 } :: int
// works for functions
fn returns_int() { 10 } :: int
x = returns_int()
</code></pre>
<p>This example would place the type <em>after</em> the function's body - for longer functions, it would likely be off-screen.
So a prefix notation seems to be my best bet:</p>
<pre><code>// me, currently - no type annotation
fn double(a int) { 2 * a }

// rust, using an arrow
fn double(a: int) -&gt; int { 2 * a }
// the arrow can be &quot;glued&quot; to the function body rather than its signature:
// signature: fn double(a: int)
// body: -&gt; int { 2 * a }
// =&gt; functions return type is int since its body returns int

// but outside of functions, this looks confusing to me:
a = -&gt; int { 12 }
</code></pre>
<h2>Actual question</h2>
<p>If the only way to explicitly specify types was to annotate a statement/code block, which syntax would be the preferred way to do this?</p>
<p>Note: Obviously, this has to be <em>optional</em> syntax - we can't just change every <code>1</code> in code to <code>1 :: int</code> or <code>int 1</code>.</p>

<syntax><functions>
Syntax for optionally specifying the return type of any statement, instead of only having this ability when declaring a function?
CC BY-SA 4.0
2023-05-23T20:33:56.413Z
The Swift way: `{ ()-> Int in 1 }`. The word “in” serves to divide the type from the body.
Bbrk24
CC BY-SA 4.0
2023-06-05T14:21:28.380Z
The conventional syntax is like `let x: int = { ... };`
kaya3
<h1>Type Ascriptions</h1>
<p>What you are asking about is called a <em>Type Ascription</em>.<br />
Haskell and derivative languages expose it via what they call <a href="https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-560003.16" rel="nofollow noreferrer"><em>Expression Type-Signatures</em></a>.<br />
It looks like this: <code>42 :: Int</code>, and you can use it like this: <code>f (42 :: Int)</code>.</p>
<p>Further than this, it can also be used to narrow down the desired type from an expression, say to remove types from an intersection, or to perform a downcast, or to select a member from an overloaded set.<br />
It may even be used to select how to compute an expression depending on functions polymorphic on their <em>return type</em>.<br />
In Haskell, you may see code like this:</p>
<pre class="lang-hs prettyprint-override"><code>class Read a where
    read: String -&gt; a

instance Read String where
    read = id

instance Read Int where
    read = parseInt

main =
    putStrLn (read &quot;42&quot; :: Int)
</code></pre>
<p>Here, the <code>read &quot;42&quot;</code> expression alone is ambiguous - has it type <code>Int</code> or <code>String</code>? - so the ascription expression narrows the type down to <code>Int</code>, the correct function is selected, and everything computes.</p>
<p>In Scala it's spelt <code>x.asInstanceOf[Int]</code>.<br />
In fact, you actually can use casts to do all of the above in C-like languages. For instance, D actually <em>requires</em> using a cast as a type ascription to take the address of a function that is overloaded (eg. <code>&amp;f</code> may fail, so you have to explicitly say <code>cast(T function(U, V)) &amp;f</code> for it to work).</p>
<blockquote>
<p>This example would place the type after the function's body - for longer functions, it would likely be off-screen</p>
</blockquote>
<p>C casts go first!</p>

CC BY-SA 4.0
2023-06-05T21:19:59.807Z
2023-06-06T15:11:43.197Z
2023-06-06T15:11:43.197Z
Longinus
CC BY-SA 4.0
2023-06-06T14:53:21.330Z
"D actually requires using a cast as a type ascription"

Isn't this ambiguous between "just use the function that returns int" vs "use the function that returns float, but then cast that float to an int"?

(btw, thanks - just knowing what this is called was very helpful for me)
Dummi26
CC BY-SA 4.0
2023-06-06T15:06:11.167Z
@Dummi26 It doesn't have to be ambiguous. For example you could unify the two `read` functions above under an intersection type (`String -> String & String -> Int`), where ambiguity is automatically solved by an upcast to `String -> (String | Int)` - at which point the language tells you to figure out for yourself what the returned value actually is. But D is not smart enough for that kind of things, and taking the address of an overloaded function without a cast makes the compiler complain.
Longinus
CC BY-SA 4.0
2023-06-06T15:10:47.350Z
@Dummi26 You can see the error here: https://run.dlang.io/is/F0xQBV
Longinus
CC BY-SA 4.0
2023-09-06T13:31:47.107Z
@Dummi26 Wouldn't that be "use function returning int" versus "cast _value_ to int" (not function) ? `cast(void function(int))` versus `cast(int)`. Of course, there's still the problem of select (valid) versus cast/force: `cast(float function(string) &f`.
Pablo H
<p>Does the Rust style of permitting type annotations on the <strong>binding itself</strong> seem amenable to you?</p>
<pre><code>s: string = {
    a: int = 10
    to_string(a * 2)
}

x: int = 10

x: int = { 10 }

// You could use this with function literals like so, if you wanted
double: fn(int) -&gt; int = ...

a: int = { 12 }
</code></pre>
<p>In my mind, this is not really about the &quot;return type&quot; of the expression, but just asserting or ascribing the type of the expression itself.</p>
<p>One big difference between this and your own proposal is that an expression level form, like <code>x :: type</code>, allows you to ascribe types to subexpressions in a more complex composite expression, e.g. <code>foo(bar(x, y :: int), z)</code>, whereas annotations on bindings would require you to decompose that expression if you wanted to ascribe a type to an inner piece.</p>

CC BY-SA 4.0
2023-06-05T14:13:04.410Z
2023-06-05T14:13:04.410Z
quiet_laika
CC BY-SA 4.0
2023-09-06T13:38:19.773Z
From what you write, it seems ascribing to expressions is more flexible/powerful than ascribing to bindings. What's the tradeoff? Are there benefits to ascribing to bindings and/or demerits to ascribing to expressions?
Pablo H
# Syntax for optionally specifying the return type of any statement, instead of only having this ability when declaring a function?
Posted by: username_0 on 2023-05-23
Background
Following a set of simple rules, I can determine the output type of any statement.
For example, adding two integers gives me an integer, list.get() gives me whatever type the list contains and so on.
A code block is just one statement containing any number of statements.
Its output type is defined as the output type of the last statement:
// s will be a string ("20")
s = {
    a = 10
    to_string(a * 2)
}

This way, function return types are also determined just from the code written in that function (they don't need to be specified), but there are cases (more complicated functions etc) where you want to be sure you can't accidentally return a wrong type and mess up the function signature - it would be nice to specify the return type you want and know that this will be enforced.
Issues with conventional syntax
I could simply add the option to specify function return types, but I have already found situations where I wanted to annotate variables with their types, too.
So instead of adding multiple syntactical ways of forcing specific types, I would prefer having only one way to specify the return type that works for every situation - for example after the statement in question:
// returns an int
x = 10
// same here
x = { 10 }
// same here, but the compiler enforces it
x = { 10 } :: int
// works for functions
fn returns_int() { 10 } :: int
x = returns_int()

This example would place the type after the function's body - for longer functions, it would likely be off-screen.
So a prefix notation seems to be my best bet:
// me, currently - no type annotation
fn double(a int) { 2 * a }

// rust, using an arrow
fn double(a: int) -> int { 2 * a }
// the arrow can be "glued" to the function body rather than its signature:
// signature: fn double(a: int)
// body: -> int { 2 * a }
// => functions return type is int since its body returns int

// but outside of functions, this looks confusing to me:
a = -> int { 12 }

Actual question
If the only way to explicitly specify types was to annotate a statement/code block, which syntax would be the preferred way to do this?
Note: Obviously, this has to be optional syntax - we can't just change every 1 in code to 1 :: int or int 1.
**Tags:** syntax functions
> **Comments:**
> **username_1**: The Swift way: `{ ()-> Int in 1 }`. The word “in” serves to divide the type from the body.  
> **username_2**: The conventional syntax is like `let x: int = { ... };`  
---
## 2 answers
### Answer by username_3 on 2023-06-05. Score: 6 | Accepted answer
Type Ascriptions
What you are asking about is called a Type Ascription.
Haskell and derivative languages expose it via what they call Expression Type-Signatures.
It looks like this: 42 :: Int, and you can use it like this: f (42 :: Int).
Further than this, it can also be used to narrow down the desired type from an expression, say to remove types from an intersection, or to perform a downcast, or to select a member from an overloaded set.
It may even be used to select how to compute an expression depending on functions polymorphic on their return type.
In Haskell, you may see code like this:
class Read a where
    read: String -> a

instance Read String where
    read = id

instance Read Int where
    read = parseInt

main =
    putStrLn (read "42" :: Int)

Here, the read "42" expression alone is ambiguous - has it type Int or String? - so the ascription expression narrows the type down to Int, the correct function is selected, and everything computes.
In Scala it's spelt x.asInstanceOf[Int].
In fact, you actually can use casts to do all of the above in C-like languages. For instance, D actually requires using a cast as a type ascription to take the address of a function that is overloaded (eg. &f may fail, so you have to explicitly say cast(T function(U, V)) &f for it to work).

This example would place the type after the function's body - for longer functions, it would likely be off-screen

C casts go first!
> **Comments:**
> **username_0** (2023-06-06): "D actually requires using a cast as a type ascription"

Isn't this ambiguous between "just use the function that returns int" vs "use the function that returns float, but then cast that float to an int"?

(btw, thanks - just knowing what this is called was very helpful for me)  
> **username_3** (2023-06-06): @Dummi26 It doesn't have to be ambiguous. For example you could unify the two `read` functions above under an intersection type (`String -> String & String -> Int`), where ambiguity is automatically solved by an upcast to `String -> (String | Int)` - at which point the language tells you to figure out for yourself what the returned value actually is. But D is not smart enough for that kind of things, and taking the address of an overloaded function without a cast makes the compiler complain.  
> **username_3** (2023-06-06): @Dummi26 You can see the error here: https://run.dlang.io/is/F0xQBV  
> **username_4** (2023-09-06): @Dummi26 Wouldn't that be "use function returning int" versus "cast _value_ to int" (not function) ? `cast(void function(int))` versus `cast(int)`. Of course, there's still the problem of select (valid) versus cast/force: `cast(float function(string) &f`.  
---
### Answer by username_5 on 2023-06-05. Score: 5
Does the Rust style of permitting type annotations on the binding itself seem amenable to you?
s: string = {
    a: int = 10
    to_string(a * 2)
}

x: int = 10

x: int = { 10 }

// You could use this with function literals like so, if you wanted
double: fn(int) -> int = ...

a: int = { 12 }

In my mind, this is not really about the "return type" of the expression, but just asserting or ascribing the type of the expression itself.
One big difference between this and your own proposal is that an expression level form, like x :: type, allows you to ascribe types to subexpressions in a more complex composite expression, e.g. foo(bar(x, y :: int), z), whereas annotations on bindings would require you to decompose that expression if you wanted to ascribe a type to an inner piece.
> **Comments:**
> **username_4** (2023-09-06): From what you write, it seems ascribing to expressions is more flexible/powerful than ascribing to bindings. What's the tradeoff? Are there benefits to ascribing to bindings and/or demerits to ascribing to expressions?  
---
