learning dart
consider fireship course (install freeship userscript)
Dart is very similar to TS/JS
import&library. every dart file is a implicitly a libraryimport 'package:lib2/lib2.dart' as foofor conflicting identifiersimport 'package:lib1/lib1.dart' show foo;imports only fooimport 'package:lib1/lib1.dart' hide foo;imports all but foo- lazy load (web only)
import 'package:greetings/hello.dart' deferred as hello;. when you need the lib invoke it:await hello.invokeLibrary();
String? name;name == null
int? a;
a ??= 3; // a = 3
-
print(null ?? 12);Prints 12. -
myObject?.someProperty?.someMethod()returns null if either myObj or someProp is null -
same lists, maps and sets like JS/TS. with inferred typing as well.
- there is a Record type
var record = ('first', a: 2, b: true, 'last');. they are anonymous, immutable, aggregate types. They are fixed size, heterogeneous and typed. - collection ifs and collection for. (like in python)
- there is a Record type
-
same arrow anon functions
-
anytype =Object? -
cascading sequence of operators
web.document.querySelector('#confirm')
?..textContent = 'Confirm'
..classList.add('important')
..onClick.listen((e) => web.window.alert('Confirmed!'))
..scrollIntoView();
// these are all methods in `button`
// can also be used to set property values of an object
- dart doesn't have
public,privateandprotected. if an identifier starts with an underscore (_foo) it is private to it's library convention. - getters and setters with
getandset. try,on,catchkeywords for error handling. Dart providesExceptionandErrorclasses. To raise an exception usethrow- Dart tools report errors and warnings. Warnings don't prevent your program from running and errors do. Errors can be runtime or compile time
function params
int sumUpToFive(int a, [int b = 2, int c = 3, int d = 4, int e = 5]) {}
the parameters wrapped in [] are optional, their default value is null unless a default value is provided. they are always last in a function's param list.
there is also named parameters that are wrapped in {}.
when you call a fn with named params you must specify the name of the param and pass the value fn(name='andres')
variables
varlate, used for non-null vars that are initialized after its declaration and lazily initializing a var.finalvsconst
const is compile time constant.
final can only be set once.
instace variables (variables declared inside a class) can be final, not const.typedeftype aliasing- object destructuring:
var (a, [b, c]) = ('str', [1, 2]);a bit dif from JS, using [] instead of {}
inheritance
- single inheritance with
extends. refer superclass withsuper @overrideannotation, for overriding instance methods, getters & setters. the method signature must be the same (or be of inherited nature).- mixins are a way to reuse code in multiple class hierarchies.
mixin Piloted {
int astronauts = 1;
void describeCrew() {
print('Number of astronauts: $astronauts');
}
}
---
class PilotedCraft extends Spacecraft with Piloted {
// PilotedCraft now has attrs and method of both
}
- all classes implicitly define an interface, therefore you can implement any class
class MockSpaceship implements Spacecraft {}. but you can also explicitly declare it with theinterfacekeyword. abstractclasses that can be implemented or extended by a concrete class.
enums
enums are kinda weird and seem to be defined or behave sorta like a class.
Asynchronous programming
Futures, andasyncandawait
Futures are the same as JS futures
http.get('https://example.com').then((response) {
if (response.statusCode == 200) {
print('Success!');
}
}
// http.get() immediately returns a Future that holds on to the callback until the request resolves.
This same model is how Stream works. Stream provide values in the future and repeatedly over time.
Stream, andawait-forandyield.
await-foris a type of for loop that executes each subsequent iteration of the loop as new values are provided. It's used to 'loop over' streams.
example:
Stream<int> sumStream(Stream<int> stream) async* {
var sum = 0;
await for (final value in stream) {
yield sum += value;
}
}
concurrency programming
a common solution for concurrency are shared-memory threads but shared state concurrency is error prone and can lead to complicated code.
- isolates are for moving processes to separate cpu cores
all dart code runs in isolates. isolates have their own isolated memory and single thread running an event loop.
the event loop is responsible for executing the program's code. all events are added to the event queue.
isolates can share communicate with message passing, but none of the state in an isolate is accessible by others.
if the UI becomes unresponsive due to a large time-consuming computation, consider offloading it to a worker isolate (background worker).
since isolates use separate mem, if you have a global mutable var on the main isolate and mutate it on a spawned isolate, the original var will remain untouched.
isolates are not supported on Web. can use web workers there instead which are similar but differ from isolates.