|
| 1 | +# Attribute |
| 2 | + |
| 3 | +Attributes are annotations placed before structures in source code. They take the form `#attribute(...)`. |
| 4 | +An attribute occupies the entire line, and newlines are not allowed within it. |
| 5 | +Attributes do not normally affect the meaning of programs. Unused attributes will be reported as warnings. |
| 6 | + |
| 7 | +The syntax of attributes is defined as follows: |
| 8 | + |
| 9 | +``` |
| 10 | +attribute ::= '#' attribute-name |
| 11 | + | '#' attribute-name '(' properties ')' |
| 12 | +
|
| 13 | +attribute-name ::= LIDENT | LIDENT '.' LIDENT |
| 14 | +
|
| 15 | +properties ::= property (',' property)* |
| 16 | +
|
| 17 | +property ::= expr | LIDENT '=' expr |
| 18 | +
|
| 19 | +expr ::= LIDENT | UIDENT | STRING | 'true' | 'false' |
| 20 | + | LIDENT '.' LIDENT |
| 21 | + | LIDENT '(' properties ')' |
| 22 | + | LIDENT '.' LIDENT '(' properties ')' |
| 23 | +``` |
| 24 | + |
| 25 | +The attributes has two forms: the built-in attributes and user-defined attributes. |
| 26 | +Built-in attributes are recognized by the MoonBit compiler and have specific meanings. |
| 27 | +User-defined attributes are ignored by the compiler, but can be used by external tools, |
| 28 | +via parsing the source code. |
| 29 | + |
| 30 | +```{note} |
| 31 | +MoonBit is designed not to support runtime reflection. It's easy to abuse, making it impossible for toolchains (e.g., the compiler) to catch errors at compile time, which makes code harder to maintain. It also negatively impacts performance optimization. |
| 32 | +
|
| 33 | +We perfer to use compile-time code generation, keeping the benefits of static typing and performance (should also be used judiciously to avoid unnecessary complexity). |
| 34 | +``` |
| 35 | + |
| 36 | +## Deprecated Attribute |
| 37 | + |
| 38 | +The `#deprecated` attribute is used to mark an API as deprecated. MoonBit emits |
| 39 | +a warning when the deprecated API is used, and if the API is listed in completion, |
| 40 | +it will be shown with a strikethrough style. For example: |
| 41 | + |
| 42 | +```{literalinclude} /sources/language/src/attributes/top.mbt |
| 43 | +:language: moonbit |
| 44 | +:start-after: start deprecated |
| 45 | +:end-before: end deprecated |
| 46 | +``` |
| 47 | + |
| 48 | +The `#deprecated` attribute can be used in the following contexts: |
| 49 | + |
| 50 | +- Top-level value declarations (including `fn`, `let`, and `const`) |
| 51 | +- Top-level type declarations (including `type`, `struct`, and `enum`) |
| 52 | +- Trait method declarations |
| 53 | +- Trait default implementations |
| 54 | + |
| 55 | +It has three forms: |
| 56 | + |
| 57 | +- `#deprecated` |
| 58 | + |
| 59 | + Marks the item as deprecated with a default warning message. |
| 60 | + |
| 61 | +- `#deprecated("Use new_function instead")` |
| 62 | + |
| 63 | + Marks the item as deprecated with a custom warning message. Every time the deprecated API is used, the provided message will be displayed as a warning. |
| 64 | + |
| 65 | +- `#deprecated("Use new_function instead", skip_current_package=true)` |
| 66 | + |
| 67 | + Marks the item as deprecated with a custom warning message, but skips emitting warnings when the deprecated API is used within the same package. |
| 68 | + |
| 69 | +## Alias Attribute |
| 70 | + |
| 71 | +The `alias` attribute is used to overload operators related to indexing, or to create an alias name for a top-level function or variable. It has two forms: |
| 72 | + |
| 73 | + |
| 74 | +- `#alias("op")`: where `op` is one of the following strings representing the indexing operators: |
| 75 | + |
| 76 | + - `_[_]`: for the indexing operator |
| 77 | + - `_[_]=_` for the indexing assignment operator |
| 78 | + - `_[_:_]` for the as view operator |
| 79 | + |
| 80 | +- `#alias(id)`: where `id` is a identifier representing the alias name. |
| 81 | + |
| 82 | +Both forms allowed additional properties: |
| 83 | + |
| 84 | +- `visibility="modifier"` |
| 85 | + |
| 86 | + A labeled property, changes the visibility of the alias. The `modifier` can be `pub` or `priv`. If not specified, the alias will have the same visibility as the original function or variable. |
| 87 | + |
| 88 | +- `deprecated` or `deprecated="message"` |
| 89 | + |
| 90 | + Marks the alias as deprecated. If a message is provided, it will be displayed as a warning when the alias is used. |
| 91 | + |
| 92 | +To graceful migration from old API to new API, you can rename the old API directly, and create an alias with the old name, mark it as deprecated. For |
| 93 | +example: |
| 94 | + |
| 95 | +```{code-block} moonbit |
| 96 | +:class: top-level |
| 97 | +#alias("old_name", deprecated) |
| 98 | +fn new_name() -> Unit { |
| 99 | + ... |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +## `label_migration` Attribute |
| 104 | + |
| 105 | +The `#label_migration` attribute is used to help you safely evolve your API |
| 106 | +by warning users during the transition period. |
| 107 | + |
| 108 | +It has three following forms: |
| 109 | + |
| 110 | +- `#label_migration(id, fill=true, msg="message")` |
| 111 | + |
| 112 | + The `fill` property is used when you want to refactor an optional parameter. |
| 113 | +You can use `fill=true` when you want to eventually make an optional |
| 114 | +parameter required. You can use `fill=false` when you want to eventually |
| 115 | +remove an optional parameter. |
| 116 | + |
| 117 | + The `msg` property is an string that provides additional information about the migration. |
| 118 | + |
| 119 | + ```{code-block} moonbit |
| 120 | + :class: top-level |
| 121 | + #label_migration(x, fill=true) |
| 122 | + #label_migration(y, fill=false) |
| 123 | + fn f(x~: Int = 0, y~: Int = 1) -> Unit { ... } |
| 124 | + fn main { |
| 125 | + f(x=1, y=1) // warn on y being filled |
| 126 | + f() // warn on x not being filled |
| 127 | + } |
| 128 | + ``` |
| 129 | + |
| 130 | +- `#label_migration(id, allow_positional=true, msg="message")` |
| 131 | + |
| 132 | + The `allow_positional` property is used when you want a labelled parameter to be |
| 133 | +used without its label being provided. When the parameter is used positionally |
| 134 | +(without a label), the compiler reports a warning. This is useful when you want to change a positional parameter |
| 135 | +to a labelled parameter without breaking the downstream code. |
| 136 | + |
| 137 | + The `msg` property is an string that provides additional information about the migration. |
| 138 | + |
| 139 | + ```{code-block} moonbit |
| 140 | + :class: top-level |
| 141 | + #label_migration(x, allow_positional=true) |
| 142 | + fn f(x~: Int) -> Unit { ... } |
| 143 | +
|
| 144 | + fn main { |
| 145 | + f(42) // warn on positional argument 42 used without label |
| 146 | + } |
| 147 | + ``` |
| 148 | + |
| 149 | +- `#label_migration(id, alias=new_id, msg="message")` |
| 150 | + |
| 151 | + The alias property allows you to provide an alternative name to a labelled |
| 152 | +parameter. This is useful when renaming a parameter to maintain backward |
| 153 | +compatibility. If a warning message is provided, the compiler warns when |
| 154 | +using the alias; otherwise, the alias can be used without warnings. |
| 155 | + |
| 156 | + The `msg` property is an string that provides additional information about the migration. |
| 157 | + |
| 158 | + ```{code-block} moonbit |
| 159 | + :class: top-level |
| 160 | + #label_migration(x, alias=xx) |
| 161 | + #label_migration(x, alias=y, msg="warning") |
| 162 | + fn f(x~: Int) -> Unit { ... } |
| 163 | +
|
| 164 | + fn main { |
| 165 | + f(xx=42) // no warning |
| 166 | + f(y=42) // warning |
| 167 | + } |
| 168 | + ``` |
| 169 | + |
| 170 | +## Visibility Attribute |
| 171 | + |
| 172 | +```{note} |
| 173 | +This topic does not covered the access control. To lean more about `pub`, `pub(all)` and `priv`, see [Access Control](./packages.md#access-control). |
| 174 | +``` |
| 175 | + |
| 176 | +The `#visibility` attribute is similar to the `#deprecated` attribute, but it is used to hint that a type will change its visibility in the future. |
| 177 | +For outside usages, if the usage will be invalidated by the visibility change in future, a warning will be emitted. |
| 178 | + |
| 179 | +```{literalinclude} /sources/language/src/attributes/top.mbt |
| 180 | +:language: moonbit |
| 181 | +:start-after: start visibility |
| 182 | +:end-before: end visibility |
| 183 | +``` |
| 184 | + |
| 185 | +The `#visibility` attribute takes two arguments: `change_to` and `message`. |
| 186 | + |
| 187 | +- The `change_to` argument is a string that indicates the new visibility of the type. It can be either `"abstract"` or `"readonly"`. |
| 188 | + |
| 189 | + | `change_to` | Invalidated Usages | |
| 190 | + |-------------|--------------------| |
| 191 | + | `"readonly"` | Creating an instance of the type or mutating the fields of the instance. | |
| 192 | + | `"abstract"` | Creating an instance of the type, mutating the fields of the instance, pattern matching, or accessing fields by label. | |
| 193 | + |
| 194 | +- The `message` argument is a string that provides additional information about the visibility change. |
| 195 | + |
| 196 | +## Internal Attribute |
| 197 | + |
| 198 | +The `#internal` attribute is used to mark a function, type, or trait as internal. |
| 199 | +Any usage of the internal function or type in other modules will emit an alert warning. |
| 200 | + |
| 201 | +```{code-block} moonbit |
| 202 | +:class: top-level |
| 203 | +#internal(unsafe, "This is an unsafe function") |
| 204 | +fn unsafe_get[A](arr : Array[A]) -> A { |
| 205 | + ... |
| 206 | +} |
| 207 | +``` |
| 208 | + |
| 209 | +The internal attribute takes two arguments: `category` and `message`. |
| 210 | +`category` is a identifier that indicates the category of the alert, and `message` is a string that provides additional message for the alert. |
| 211 | + |
| 212 | +The alert warnings can be turn off by setting the `warn-list` in `moon.pkg.json`. |
| 213 | +For more detail, see [Alert](../toolchain/moon/package.md#alert-list). |
| 214 | + |
| 215 | +## External Attribute |
| 216 | + |
| 217 | +The `#external` attribute is used to mark an abstract type as external type. |
| 218 | + |
| 219 | +- For Wasm(GC) backends, it would be interpreted as `anyref`. |
| 220 | +- For JavaScript backend, it would be interpreted as `any`. |
| 221 | +- For native backends, it would be interpreted as `void*`. |
| 222 | + |
| 223 | +```{code-block} moonbit |
| 224 | +:class: top-level |
| 225 | +#external |
| 226 | +type Ptr |
| 227 | +``` |
| 228 | + |
| 229 | +## Borrow and Owned Attribute |
| 230 | + |
| 231 | +The `#borrow` and `#owned` attribute is used to indicate that a FFI takes ownership of its arguments. For more detail, see [FFI](./ffi.md#the-borrow-attribute). |
| 232 | + |
| 233 | +## `as_free_fn` Attribute |
| 234 | + |
| 235 | +The `#as_free_fn` attribute is used to mark a method that it is declared as a free function as well. |
| 236 | +It can also change the visibility of the free function, the name of the free function, and provide separate deprecation warning. |
| 237 | + |
| 238 | +```{literalinclude} /sources/language/src/misc/top.mbt |
| 239 | +:language: moonbit |
| 240 | +:start-after: start as_free_fn 1 |
| 241 | +:end-before: end as_free_fn 1 |
| 242 | +``` |
| 243 | + |
| 244 | +## Callsite Attribute |
| 245 | + |
| 246 | +The `#callsite` attribute is used to mark properties that happen at callsite. |
| 247 | + |
| 248 | +It could be `autofill`, which is to autofill the arguments [SourceLoc and ArgLoc](/language/fundamentals.md#autofill-arguments) |
| 249 | +at callsite. |
| 250 | + |
| 251 | + |
| 252 | +## Skip Attribute |
| 253 | + |
| 254 | +The `#skip` attribute is used to skip a single test block. The type checking will still be performed. |
| 255 | + |
| 256 | +## Configuration attribute |
| 257 | + |
| 258 | +The `#cfg` attribute is used to perform conditional compilation. Examples are: |
| 259 | + |
| 260 | +<!-- MANUAL CHECK --> |
| 261 | + |
| 262 | +```moonbit |
| 263 | +#cfg(true) |
| 264 | +#cfg(false) |
| 265 | +#cfg(target="wasm") |
| 266 | +#cfg(not(target="wasm")) |
| 267 | +#cfg(all(target="wasm", true)) |
| 268 | +#cfg(any(target="wasm", target="native")) |
| 269 | +``` |
0 commit comments