Skip to content

Commit 9ecc632

Browse files
committed
Doc updates
1 parent 81a17e3 commit 9ecc632

File tree

7 files changed

+53
-46
lines changed

7 files changed

+53
-46
lines changed

docs-src/_config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Learn more at https://jupyterbook.org/customize/config.html
33

44
title: Fable Python
5-
author: By the Fable community
5+
author: the Fable community
66
logo: logo.png
77

88
# Force re-execution of notebooks on each build.

docs-src/_toc.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
format: jb-book
55
root: index
66
chapters:
7-
- file: index.md
87
- file: intro.md
98
- file: introduction/dotnet-users-read-this
109
- file: introduction/py-users-read-this

docs-src/communicate/fable-from-py.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@ module Bar =
4848

4949
In some cases, it's possible to change the default behavior towards name mangling:
5050

51-
- If you want to have all members attached to a class (as in standard JS classes) and not-mangled use the `AttachMembers` attribute. But be aware **overloads won't work** in this case.
52-
- If you are not planning to use an interface to interact with JS and want to have overloaded members, you can decorate the interface declaration with the `Mangle` attribute. Note: Interfaces coming from .NET BCL (like System.Collections.IEnumerator) are mangled by default.
51+
- If you want to have all members attached to a class (as in standard Python classes) and not-mangled use the `AttachMembers` attribute. But be aware **overloads won't work** in this case.
52+
- If you are not planning to use an interface to interact with Python and want to have overloaded members, you can decorate the interface declaration with the `Mangle` attribute. Note: Interfaces coming from .NET BCL (like System.Collections.IEnumerator) are mangled by default.
5353

5454
## Common types and objects
5555

56-
Some F#/.NET types have [counterparts in JS](../dotnet/compatibility.md). Fable takes advantage of this to compile to native types that are more performant and reduce bundle size. You can also use this to improve interop when exchanging data between F# and JS. The most important common types are:
56+
Some F#/.NET types have [counterparts in JS](../dotnet/compatibility.md). Fable takes advantage of this to compile to native types that are more performant and reduce bundle size. You can also use this to improve interop when exchanging data between F# and Python. The most important common types are:
5757

58-
- **Strings and booleans** behave the same in F# and JS.
59-
- **Chars** are compiled as JS strings of length 1. This is mainly because string indexing in JS gives you another string. But you can use a char as a number with an explicit conversion like `int16 '家'`.
58+
- **Strings and booleans** behave the same in F# and Python.
59+
- **Chars** are compiled as Python strings of length 1. This is mainly because string indexing in JS gives you another string. But you can use a char as a number with an explicit conversion like `int16 '家'`.
6060
- **Numeric types** compile to JS numbers, except for `long`, `decimal` and `bigint`.
6161
- **Arrays** (and `ResizeArray`) compile to JS arrays. _Numeric arrays_ compile to [Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) in most situations, though this shouldn't make a difference for most common operations like indexing, iterating or mapping. You can disable this behavior with [the `typedArrays` option](https://www.npmjs.com/package/fable-loader#options).
6262
- Any **IEnumerable** (or `seq`) can be traversed in JS as if it were an [Iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables).

docs-src/communicate/py-from-fable.md

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
# Call Python from Fable
22

3-
Interoperability is a matter of trust between your statically typed F# code and your untyped dynamic JS code. In order to mitigate risks, Fable gives you several possibilities, amongst them type safety through interface contracts. Sometimes it may sound more convenient to just call JS code in a more dynamic fashion, although be aware by doing this potential bugs will not be discovered until runtime.
3+
Interoperability is a matter of trust between your statically typed F# code and your untyped dynamic JS code. In order
4+
to mitigate risks, Fable gives you several possibilities, amongst them type safety through interface contracts.
5+
Sometimes it may sound more convenient to just call JS code in a more dynamic fashion, although be aware by doing this
6+
potential bugs will not be discovered until runtime.
47

58
We'll describe both the safe way and the dynamic way and then it will be up to you to decide. Let's start!
69

710
## Adding the JS library to the project
811

9-
The very first thing to do is add the library to our project. Since we always have a `package.json` file, we'll just add the wanted library to our project using either `npm install my-awesome-js-library`. The library will then be available in the `node_modules` folder.
12+
The very first thing to do is add the library to our project. Since we always have a `package.json` file, we'll just add
13+
the wanted library to our project using either `npm install my-awesome-js-library`. The library will then be available
14+
in the `node_modules` folder.
1015

1116
> If your library is in a file, just skip this step.
1217
1318
## Type safety with Imports and Interfaces
1419

15-
To use code from JS libraries first you need to import it into F#. For this Fable uses [ES2015 imports](https://developer.mozilla.org/en/docs/web/JavaScript/reference/statements/import), which can be later transformed to other JS module systems like `commonjs` or `amd` by [Babel](https://babeljs.io/docs/en/plugins#modules).
20+
To use code from JS libraries first you need to import it into F#. For this Fable uses [ES2015
21+
imports](https://developer.mozilla.org/en/docs/web/JavaScript/reference/statements/import), which can be later
22+
transformed to other JS module systems like `commonjs` or `amd` by [Babel](https://babeljs.io/docs/en/plugins#modules).
1623

17-
There are two ways to declare ES2015 imports in Fable: by using either the **Import attribute** or the **import expressions**. The `ImportAttribute` can decorate members, types or modules and works as follows:
24+
There are two ways to declare ES2015 imports in Fable: by using either the **Import attribute** or the **import
25+
expressions**. The `ImportAttribute` can decorate members, types or modules and works as follows:
1826

1927
```fsharp
2028
// Namespace imports
@@ -34,28 +42,28 @@ You can also use the following alias attributes:
3442

3543
```fsharp
3644
open Fable.Core
37-
open Fable.Core.JsInterop
45+
open Fable.Core.PyInterop
3846
3947
// Same as Import("*", "my-module")
4048
[<ImportAll("my-module")>]
41-
let myModule: obj = jsNative
49+
let myModule: obj = nativeOnly
4250
4351
// Same as Import("default", "my-module")
4452
[<ImportDefault("my-module")>]
45-
let myModuleDefaultExport: obj = jsNative
53+
let myModuleDefaultExport: obj = nativeOnly
4654
4755
// The member name is taken from decorated value, here `myFunction`
4856
[<ImportMember("my-module")>]
49-
let myFunction(x: int): int = jsNative
57+
let myFunction(x: int): int = nativeOnly
5058
```
5159

5260
If the value is globally accessible in JS, you can use the `Global` attribute with an optional name parameter instead.
5361

5462
```fsharp
55-
let [<Global>] console: JS.Console = jsNative
63+
let [<Global>] console: JS.Console = nativeOnly
5664
5765
// You can pass a string argument if you want to use a different name in your F# code
58-
let [<Global("console")>] logger: JS.Console = jsNative
66+
let [<Global("console")>] logger: JS.Console = nativeOnly
5967
```
6068

6169
### Importing relative paths when using an output directory
@@ -64,25 +72,25 @@ If you are putting the generated JS files in an output directory using Fable's `
6472

6573
```fsharp
6674
[<ImportDefault("${outDir}/../styles/styles.module.css")>]
67-
let styles: CssModule = jsNative
75+
let styles: CssModule = nativeOnly
6876
```
6977

7078
Let's say we're compiling with the `-o build` option and the file ends up in the `build/Components` directory. The generated code will look like:
7179

7280
```js
73-
import styles from "../../styles/styles.module.css"
81+
import styles from "../../styles/styles.module.css";
7482
```
7583

7684
### OOP Class definition and inheritance
7785

78-
Assuming we need to import a JS class, we can represent it in F# using a standard class declaration with an `Import` attribute. In this case we use `jsNative` as a dummy implementation for its members as the actual implementation will come from JS. When using `jsNative` don't forget to add the return type to the member!
86+
Assuming we need to import a JS class, we can represent it in F# using a standard class declaration with an `Import` attribute. In this case we use `nativeOnly` as a dummy implementation for its members as the actual implementation will come from JS. When using `nativeOnly` don't forget to add the return type to the member!
7987

8088
```fsharp
8189
[<Import("DataManager", from="library/data")>]
8290
type DataManager<'Model> (conf: Config) =
83-
member _.delete(data: 'Model): Promise<'Model> = jsNative
84-
member _.insert(data: 'Model): Promise<'Model> = jsNative
85-
member _.update(data: 'Model): Promise<'Model> = jsNative
91+
member _.delete(data: 'Model): Promise<'Model> = nativeOnly
92+
member _.insert(data: 'Model): Promise<'Model> = nativeOnly
93+
member _.update(data: 'Model): Promise<'Model> = nativeOnly
8694
```
8795

8896
From this point it is possible to use it or even to inherit from it as it is usually done on regular F#, [see the official F# documentation](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/inheritance). If you want to inherit and override a member, F# requires you to declare the member as `abstract` in the base class, with a default implementation if you want to make it also directly usable from the base class. For example:
@@ -92,7 +100,7 @@ From this point it is possible to use it or even to inherit from it as it is usu
92100
[<Import("DataManager", from="library.data")>]
93101
type DataManager<'T> (conf: Config) =
94102
abstract update: data: 'T -> Promise<'T>
95-
default _.update(data: 'T): Promise<'T> = jsNative
103+
default _.update(data: 'T): Promise<'T> = nativeOnly
96104
97105
// This class lives in our code
98106
type MyDataManager<'T>(config) =
@@ -146,15 +154,15 @@ Now let's use this:
146154

147155
```fsharp
148156
[<ImportAll("path/to/alert.js")>]
149-
let mylib: IAlert = jsNative
157+
let mylib: IAlert = nativeOnly
150158
```
151159

152160
Here we use the `ImportAll` attribute, which is the same as `Import("*", "path/to/alert.js")` just like we described earlier.
153161

154162
- step 1: We specify the elements we wish to use. Here `*` means: "take everything that's been exported"
155163
- step 2: we set the path to our js library.
156164
- step 3: we create a let binding called `mylib` to map the js library.
157-
- step 4: we use the `jsNative` keyword to say that `mylib` is just a placeholder for the JavaScript native implementation.
165+
- step 4: we use the `nativeOnly` keyword to say that `mylib` is just a placeholder for the JavaScript native implementation.
158166

159167
Now we can use this:
160168

@@ -187,7 +195,7 @@ we could use the same method we used with `alert.js`:
187195
abstract drawBubble: (id:string) -> unit
188196
189197
[<ImportAll("path/to/Canvas.js")>]
190-
let mylib: ICanvas = jsNative
198+
let mylib: ICanvas = nativeOnly
191199
192200
mylib.drawSmiley "smiley" // etc..
193201
```
@@ -250,7 +258,7 @@ You can use the `Emit` attribute to decorate a function. Every call to the funct
250258
open Fable.Core
251259
252260
[<Emit("$0 + $1")>]
253-
let add (x: int) (y: string): string = jsNative
261+
let add (x: int) (y: string): string = nativeOnly
254262
255263
let result = add 1 "2"
256264
```
@@ -260,19 +268,19 @@ When you don't know the exact number of arguments you can use the following synt
260268
```fsharp
261269
type Test() =
262270
[<Emit("$0($1...)")>]
263-
member __.Invoke([<ParamArray>] args: int[]): obj = jsNative
271+
member __.Invoke([<ParamArray>] args: int[]): obj = nativeOnly
264272
```
265273

266274
It's also possible to pass syntax conditioned to optional parameters:
267275

268276
```fsharp
269277
type Test() =
270278
[<Emit("$0[$1]{{=$2}}")>]
271-
member __.Item with get(): float = jsNative and set(v: float): unit = jsNative
279+
member __.Item with get(): float = nativeOnly and set(v: float): unit = nativeOnly
272280
273281
// This syntax means: if second arg evals to true in JS print 'i' and nothing otherwise
274282
[<Emit("new RegExp($0,'g{{$1?i:}}')")>]
275-
member __.ParseRegex(pattern: string, ?ignoreCase: bool): Regex = jsNative
283+
member __.ParseRegex(pattern: string, ?ignoreCase: bool): Regex = nativeOnly
276284
```
277285

278286
The content of `Emit` will actually be parsed by [Babel](https://babeljs.io/) so it will still be validated somehow. However, it's not advised to abuse this method, as the code won't be checked by the F# compiler.
@@ -294,7 +302,7 @@ export default class MyClass {
294302
return this._value;
295303
}
296304

297-
set value( newValue ) {
305+
set value(newValue) {
298306
this._value = newValue;
299307
}
300308

@@ -332,7 +340,7 @@ type MyClassStatic =
332340
abstract getPI : unit-> float
333341
```
334342

335-
:::info
343+
:::{note}
336344
We could have used a class declaration with dummy implementations as we did with DataManager above, but you will find that in Fable bindings it's common to split the instance and static parts of a JS type in two interfaces to overcome some restrictions of the F# type system or to be able to deal with JS classes as values. In this case, by convention `Create` denotes the constructor.
337345
:::
338346

@@ -342,7 +350,7 @@ Last but not least, let's import MyClass:
342350

343351
```fsharp
344352
[<ImportDefault("../public/MyClass.js")>]
345-
let MyClass : MyClassStatic = jsNative
353+
let MyClass : MyClassStatic = nativeOnly
346354
```
347355

348356
Now it's possible to use our JS class. Let's see the complete code:
@@ -359,7 +367,7 @@ type MyClassStatic =
359367
abstract getPI : unit-> float
360368
361369
[<ImportDefault("../public/MyClass.js")>]
362-
let MyClass : MyClassStatic = jsNative
370+
let MyClass : MyClassStatic = nativeOnly
363371
364372
let myObject = MyClass.Create(40, 42)
365373
@@ -383,7 +391,7 @@ It's possible to combine the `Import` and `Emit` attributes. So we can import an
383391
```fsharp
384392
[<ImportDefault("../public/MyClass.js")>]
385393
[<Emit("new $0({ value: $1, awesomeness: $2 })")>]
386-
let createMyClass(value: 'T, awesomeness: 'T) : MyClass<'T> = jsNative
394+
let createMyClass(value: 'T, awesomeness: 'T) : MyClass<'T> = nativeOnly
387395
```
388396

389397
## Other special attributes
@@ -406,7 +414,7 @@ myLib.myMethod(String "test")
406414
```
407415

408416
```js
409-
myLib.myMethod("test")
417+
myLib.myMethod("test");
410418
```
411419

412420
`Fable.Core` already includes predefined erased types which can be used as follows:
@@ -433,7 +441,7 @@ myMethod !^testValue
433441
myMethod !^2.3
434442
```
435443

436-
:::info
444+
:::{note}
437445
Please note erased unions are mainly intended for typing the signature of imported JS functions and not as a cheap replacement of `Choice`. It's possible to do pattern matching against an erased union type but this will be compiled as type testing, and since **type testing is very weak in Fable**, this is only recommended if the generic arguments of the erased union are types that can be easily told apart in the JS runtime (like a string, a number and an array).
438446
:::
439447

@@ -476,7 +484,7 @@ myLib.myMethod(Vertical, Horizontal)
476484

477485
```js
478486
// js output
479-
myLib.myMethod("vertical", "Horizontal")
487+
myLib.myMethod("vertical", "Horizontal");
480488
```
481489

482490
## Plain Old JavaScript Objects

docs-src/dotnet/compatibility.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ There is also support to convert between numeric types and to parse strings, che
3939

4040
### Caveats
4141

42-
- All numeric types become JS `number` (64-bit floating type), except for `int64`, `uint64`, `bigint` and `decimal`. Check the [Numeric Types](numbers.html) section to learn more about the differences between .NET and JS.
42+
- All numeric types become JS `number` (64-bit floating type), except for `int64`, `uint64`, `bigint` and `decimal`. Check the [Numeric Types](numbers.md) section to learn more about the differences between .NET and JS.
4343
- Numeric arrays are compiled to [Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) when possible.
4444
- No bound checks for numeric types (unless you do explicit conversions like `byte 500`) nor for array indices.
4545
- `Regex` will always behave as if passed `RegexOptions.ECMAScript` flag (e.g., no negative look-behind or named groups).
@@ -69,9 +69,9 @@ MailboxProcessor | fable-core/MailboxProcessor (limited support)
6969

7070
### Caveats II
7171

72-
- Options are **erased** in JS (`Some 5` becomes just `5` in JS and `None` translates to `null`). This is needed for example, to represent TypeScript [optional properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#optional-properties). However in a few cases (like nested options) there is an actual representation of the option in the runtime.
72+
- Options are **erased** in Python (`Some 5` becomes just `5` in Python and `None` translates to `null`). This is needed for example, to represent Python [optional properties](https://docs.python.org/3/library/typing.html#typing.Optional). However in a few cases (like nested options) there is an actual representation of the option in the runtime.
7373
- `Async.RunSynchronously` is not supported.
74-
- `MailboxProcessor` is single-threaded in JS and currently only `Start`, `Receive`, `Post` and `PostAndAsyncReply` are implemented (`cancellationToken` or `timeout` optional arguments are not supported).
74+
- `MailboxProcessor` is single-threaded in Python and currently only `Start`, `Receive`, `Post` and `PostAndAsyncReply` are implemented (`cancellationToken` or `timeout` optional arguments are not supported).
7575

7676
## Object Oriented Programming
7777

docs-src/new-to-fsharp/let-keyword.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ Don't worry too much if you don't fully grasp the above code, the main goal of t
5353

5454
The main differences that the `let` keyword in F# has from assignments in Python are:
5555

56-
- In JavaScript one would use `let` to define a named variable, and its value can be reassigned which is not the case in F#.
57-
- In JavaScript `let` is scope bound, so one can declare a new variable with an already used name as long as it is in a different scope, in F# that can be done within the same scope.
56+
- In Python one would use an assignment to define a named variable, and its value can be reassigned which is not the case in F#.
57+
- In Python assignments are scope bound, so one can declare a new variable with an already used name as long as it is in a different scope, in F# that can be done within the same scope.
5858

5959
### References
6060

docs-src/your-fable-project/project-file.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Unlike JS, F# projects require all sources to be listed **in compilation order** in an `.fsproj` file. This may look quite restrictive at first, but it does have [some advantages](https://fsharpforfunandprofit.com/posts/cyclic-dependencies/).
44
Since an F# project takes its roots from the .NET ecosystem, we need to follow a few obligatory steps in order to add a file to an F# project.
55

6-
:::info
6+
:::{note}
77
Many F# IDEs already provide commands to perform operations like creating a project or adding/removing a file. The steps below are only necessary if you want to do this manually.
88
:::
99

@@ -51,7 +51,7 @@ For example, if we have have an app with two files, named `MyAwesomeFeature.fs`
5151
<ItemGroup>
5252
```
5353

54-
:::info
54+
:::{note}
5555
Please be aware that in F#, **file order is important.** For instance, if `App.fs` calls `MyAwesomeFeature.fs`, then you must place `MyAwesomeFeature.fs` above `App.fs`.
5656
:::
5757

0 commit comments

Comments
 (0)