Skip to content

Commit 501c48f

Browse files
committed
Fixes to inline.md
1 parent ede7aa8 commit 501c48f

File tree

1 file changed

+62
-25
lines changed

1 file changed

+62
-25
lines changed

docs/docs/reference/metaprogramming/inline.md

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ layout: doc-page
33
title: Inline
44
---
55

6-
## Inline (blackbox/whitebox)
6+
## Inline Definitions
77

88
`inline` is a new [soft modifier](../soft-modifier.html) that guarantees that a
99
definition will be inlined at the point of use. Example:
@@ -165,6 +165,8 @@ Scala 2 ignores the `@forceInline` annotation, so one must use both
165165
annotations to guarantee inlining for Dotty and at the same time hint inlining
166166
for Scala 2 (i.e. `@forceInline @inline`).
167167

168+
<!--- (Commented out since the docs and implementation differ)
169+
168170
### Evaluation Rules
169171
170172
As you noticed by the examples above a lambda of the form
@@ -185,6 +187,7 @@ corresponding binding is omitted and `y` is used instead of `x_i` in `B`.
185187
186188
If a `inline` modifier is given for parameters, corresponding arguments must be
187189
pure expressions of constant type.
190+
-->
188191

189192
#### The definition of constant expression
190193

@@ -194,17 +197,11 @@ constant expressions in the sense defined by the [SLS §
194197
including _platform-specific_ extensions such as constant folding of pure
195198
numeric computations.
196199

197-
### Specializing Inline (Whitebox)
200+
## Specializing Inline (Whitebox)
198201

199202
Inline methods support the ` <: T` return type syntax. This means that the return type
200203
of the inline method is going to be specialized to a more precise type upon
201-
expansion.
202-
203-
Consider the example below where the inline method `choose` can return an object
204-
of any of the two dynamic types. The subtype relationship is `B <: A`. Since we
205-
use the specializing inline syntax, the static types of the `val`s are inferred
206-
accordingly. Consequently, calling `meth` on `obj2` is not a compile-time error
207-
as `obj2` will be of type `B`.
204+
expansion. Example:
208205

209206
```scala
210207
class A
@@ -220,9 +217,20 @@ inline def choose(b: Boolean) <: A = {
220217
val obj1 = choose(true) // static type is A
221218
val obj2 = choose(false) // static type is B
222219

223-
obj1.meth() // compile-time error
224-
obj2.meth() // OK
220+
// obj1.meth() // compile-time error: `meth` is not defined on `A`
221+
obj2.meth() // OK
225222
```
223+
Here, the inline method `choose` returns an object of either of the two dynamic types
224+
`A` and `B`. If `choose` had been declared with a normal return type `: A`, the result
225+
of its expansion would always be of type `A`, even though the computed value might be
226+
of type `B`. The inline method is "blackbox" in the sense that details of its
227+
implementation do not leak out. But with the specializing return type `<: A`,
228+
the type of the expansion is the type of the expanded body. If the argument `b`
229+
is `true`, that type is `A`, otherwise it is `B`. Consequently, calling `meth` on `obj2`
230+
type-checks since `obj2` has the same type as the expansion of `choose(false)`, which is `B`.
231+
Inline methods with specializing return types are "whitebox" in that the type
232+
of an application of such a method can be more specialized than its declared
233+
return type, depending on how the method expands.
226234

227235
In the following example, we see how the return type of `zero` is specialized to
228236
the singleton type `0` permitting the addition to be ascribed with the correct
@@ -234,12 +242,42 @@ inline def zero() <: Int = 0
234242
final val one: 1 = zero() + 1
235243
```
236244

237-
#### Inline Match
245+
## Inline Conditionals
246+
247+
If the condition of an if-then-else expressions is a constant, the expression simplifies to
248+
the selected branch. Prefixing an if-then-else expression with `inline` forces
249+
the condition to be a constant, and thus guarantees that the conditional will always
250+
simplify.
251+
252+
Example:
253+
254+
```scala
255+
inline def update(delta: Int) =
256+
inline if (delta >= 0) increaseBy(delta)
257+
else decreaseByf(delta)
258+
```
259+
A call `update(22)` would rewrite to `increaseBy(22`. But if `update` was called with
260+
a value that was not a compile-time constant, we would get a compile time error like the one
261+
below:
262+
```
263+
| inline if (delta >= 0) ???
264+
| ^
265+
| cannot reduce inline if
266+
| its condition
267+
| delta >= 0
268+
| is not a constant value
269+
| This location is in code that was inlined at ...
270+
```
271+
272+
## Inline Matches
238273

239274
A `match` expression in the body of an `inline` method definition may be
240275
prefixed by the `inline` modifier. If there is enough static information to
241276
unambiguously take a branch, the expression is reduced to that branch and the
242-
type of the result is taken. The example below defines an inline method with a
277+
type of the result is taken. If not, a compile-time error is raised that
278+
reports that the match cannot be reduced.
279+
280+
The example below defines an inline method with a
243281
single inline match expression that picks a case based on its static type:
244282

245283
```scala
@@ -275,12 +313,11 @@ val intTwo: 2 = natTwo
275313

276314
`natTwo` is inferred to have the singleton type 2.
277315

278-
#### scala.compiletime._
316+
## The scala.compiletime Package
279317

280-
This package contains helper definitions providing support for compile time
281-
operations over values.
318+
The `scala.compiletime` package contains helper definitions that provide support for compile time operations over values. They are described in the following.
282319

283-
##### Const Value & Const Value Opt
320+
#### `constValue`, `constValueOpt`, and the `S` combinator
284321

285322
`constvalue` is a function that produces the constant value represented by a
286323
type.
@@ -302,7 +339,7 @@ enabling us to handle situations where a value is not present. Note that `S` is
302339
the type of the successor of some singleton type. For example the type `S[1]` is
303340
the singleton type `2`.
304341

305-
##### Erased Value
342+
#### `erasedValue`
306343

307344
We have seen so far inline methods that take terms (tuples and integers) as
308345
parameters. What if we want to base case distinctions on types instead? For
@@ -318,7 +355,7 @@ erased def erasedValue[T]: T = ???
318355
The `erasedValue` function _pretends_ to return a value of its type argument
319356
`T`. In fact, it would always raise a `NotImplementedError` exception when
320357
called. But the function can in fact never be called, since it is declared
321-
`erased`, so can be only used a compile-time during type checking.
358+
`erased`, so can be only used at compile-time during type checking.
322359

323360
Using `erasedValue`, we can then define `defaultValue` as follows:
324361

@@ -363,19 +400,19 @@ final val two = toInt[Succ[Succ[Zero]]]
363400
behavior. Since `toInt` performs static checks over the static type of `N` we
364401
can safely use it to scrutinize its return type (`S[S[Z]]` in this case).
365402

366-
##### Error
403+
#### `error`
367404

368-
This package provides a compile time `error` definition with the following signature:
405+
The `error` method is used to produce user-defined compile errors during inline expansion.
406+
It has the following signature:
369407

370408
```scala
371409
inline def error(inline msg: String, objs: Any*): Nothing
372410
```
373411

374-
The purpose of this is to expand at the point of use, an error message (a
375-
constant string) and append with commas, compile time values passed in the
376-
`objs` param.
412+
If an inline expansion results in a call `error(msgStr)` the compiler
413+
produces an error message containing the given `msgStr`.
377414

378-
#### Implicit Match
415+
## Implicit Matches
379416

380417
It is foreseen that many areas of typelevel programming can be done with rewrite
381418
methods instead of implicits. But sometimes implicits are unavoidable. The

0 commit comments

Comments
 (0)