You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs-src/communicate/fable-from-py.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,15 +48,15 @@ module Bar =
48
48
49
49
In some cases, it's possible to change the default behavior towards name mangling:
50
50
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.
53
53
54
54
## Common types and objects
55
55
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:
57
57
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 '家'`.
60
60
-**Numeric types** compile to JS numbers, except for `long`, `decimal` and `bigint`.
61
61
-**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).
62
62
- 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).
Copy file name to clipboardExpand all lines: docs-src/communicate/py-from-fable.md
+40-32Lines changed: 40 additions & 32 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,20 +1,28 @@
1
1
# Call Python from Fable
2
2
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.
4
7
5
8
We'll describe both the safe way and the dynamic way and then it will be up to you to decide. Let's start!
6
9
7
10
## Adding the JS library to the project
8
11
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.
10
15
11
16
> If your library is in a file, just skip this step.
12
17
13
18
## Type safety with Imports and Interfaces
14
19
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).
16
23
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:
18
26
19
27
```fsharp
20
28
// Namespace imports
@@ -34,28 +42,28 @@ You can also use the following alias attributes:
34
42
35
43
```fsharp
36
44
open Fable.Core
37
-
open Fable.Core.JsInterop
45
+
open Fable.Core.PyInterop
38
46
39
47
// Same as Import("*", "my-module")
40
48
[<ImportAll("my-module")>]
41
-
let myModule: obj = jsNative
49
+
let myModule: obj = nativeOnly
42
50
43
51
// Same as Import("default", "my-module")
44
52
[<ImportDefault("my-module")>]
45
-
let myModuleDefaultExport: obj = jsNative
53
+
let myModuleDefaultExport: obj = nativeOnly
46
54
47
55
// The member name is taken from decorated value, here `myFunction`
48
56
[<ImportMember("my-module")>]
49
-
let myFunction(x: int): int = jsNative
57
+
let myFunction(x: int): int = nativeOnly
50
58
```
51
59
52
60
If the value is globally accessible in JS, you can use the `Global` attribute with an optional name parameter instead.
53
61
54
62
```fsharp
55
-
let [<Global>] console: JS.Console = jsNative
63
+
let [<Global>] console: JS.Console = nativeOnly
56
64
57
65
// 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
59
67
```
60
68
61
69
### 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 `
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:
71
79
72
80
```js
73
-
importstylesfrom"../../styles/styles.module.css"
81
+
importstylesfrom"../../styles/styles.module.css";
74
82
```
75
83
76
84
### OOP Class definition and inheritance
77
85
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!
79
87
80
88
```fsharp
81
89
[<Import("DataManager", from="library/data")>]
82
90
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
86
94
```
87
95
88
96
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
Here we use the `ImportAll` attribute, which is the same as `Import("*", "path/to/alert.js")` just like we described earlier.
153
161
154
162
- step 1: We specify the elements we wish to use. Here `*` means: "take everything that's been exported"
155
163
- step 2: we set the path to our js library.
156
164
- 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.
158
166
159
167
Now we can use this:
160
168
@@ -187,7 +195,7 @@ we could use the same method we used with `alert.js`:
187
195
abstract drawBubble: (id:string) -> unit
188
196
189
197
[<ImportAll("path/to/Canvas.js")>]
190
-
let mylib: ICanvas = jsNative
198
+
let mylib: ICanvas = nativeOnly
191
199
192
200
mylib.drawSmiley "smiley" // etc..
193
201
```
@@ -250,7 +258,7 @@ You can use the `Emit` attribute to decorate a function. Every call to the funct
250
258
open Fable.Core
251
259
252
260
[<Emit("$0 + $1")>]
253
-
let add (x: int) (y: string): string = jsNative
261
+
let add (x: int) (y: string): string = nativeOnly
254
262
255
263
let result = add 1 "2"
256
264
```
@@ -260,19 +268,19 @@ When you don't know the exact number of arguments you can use the following synt
260
268
```fsharp
261
269
type Test() =
262
270
[<Emit("$0($1...)")>]
263
-
member __.Invoke([<ParamArray>] args: int[]): obj = jsNative
271
+
member __.Invoke([<ParamArray>] args: int[]): obj = nativeOnly
264
272
```
265
273
266
274
It's also possible to pass syntax conditioned to optional parameters:
267
275
268
276
```fsharp
269
277
type Test() =
270
278
[<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
272
280
273
281
// This syntax means: if second arg evals to true in JS print 'i' and nothing otherwise
274
282
[<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
276
284
```
277
285
278
286
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 {
294
302
returnthis._value;
295
303
}
296
304
297
-
setvalue(newValue) {
305
+
setvalue(newValue) {
298
306
this._value= newValue;
299
307
}
300
308
@@ -332,7 +340,7 @@ type MyClassStatic =
332
340
abstract getPI : unit-> float
333
341
```
334
342
335
-
:::info
343
+
:::{note}
336
344
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.
337
345
:::
338
346
@@ -342,7 +350,7 @@ Last but not least, let's import MyClass:
342
350
343
351
```fsharp
344
352
[<ImportDefault("../public/MyClass.js")>]
345
-
let MyClass : MyClassStatic = jsNative
353
+
let MyClass : MyClassStatic = nativeOnly
346
354
```
347
355
348
356
Now it's possible to use our JS class. Let's see the complete code:
@@ -359,7 +367,7 @@ type MyClassStatic =
359
367
abstract getPI : unit-> float
360
368
361
369
[<ImportDefault("../public/MyClass.js")>]
362
-
let MyClass : MyClassStatic = jsNative
370
+
let MyClass : MyClassStatic = nativeOnly
363
371
364
372
let myObject = MyClass.Create(40, 42)
365
373
@@ -383,7 +391,7 @@ It's possible to combine the `Import` and `Emit` attributes. So we can import an
let createMyClass(value: 'T, awesomeness: 'T) : MyClass<'T> = jsNative
394
+
let createMyClass(value: 'T, awesomeness: 'T) : MyClass<'T> = nativeOnly
387
395
```
388
396
389
397
## Other special attributes
@@ -406,7 +414,7 @@ myLib.myMethod(String "test")
406
414
```
407
415
408
416
```js
409
-
myLib.myMethod("test")
417
+
myLib.myMethod("test");
410
418
```
411
419
412
420
`Fable.Core` already includes predefined erased types which can be used as follows:
@@ -433,7 +441,7 @@ myMethod !^testValue
433
441
myMethod !^2.3
434
442
```
435
443
436
-
:::info
444
+
:::{note}
437
445
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).
Copy file name to clipboardExpand all lines: docs-src/dotnet/compatibility.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,7 +39,7 @@ There is also support to convert between numeric types and to parse strings, che
39
39
40
40
### Caveats
41
41
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.
43
43
- Numeric arrays are compiled to [Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) when possible.
44
44
- No bound checks for numeric types (unless you do explicit conversions like `byte 500`) nor for array indices.
45
45
-`Regex` will always behave as if passed `RegexOptions.ECMAScript` flag (e.g., no negative look-behind or named groups).
- 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.
73
73
-`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).
Copy file name to clipboardExpand all lines: docs-src/new-to-fsharp/let-keyword.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff 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
53
53
54
54
The main differences that the `let` keyword in F# has from assignments in Python are:
55
55
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.
Copy file name to clipboardExpand all lines: docs-src/your-fable-project/project-file.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@
3
3
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/).
4
4
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.
5
5
6
-
:::info
6
+
:::{note}
7
7
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.
8
8
:::
9
9
@@ -51,7 +51,7 @@ For example, if we have have an app with two files, named `MyAwesomeFeature.fs`
51
51
<ItemGroup>
52
52
```
53
53
54
-
:::info
54
+
:::{note}
55
55
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`.
0 commit comments