General Dart Flashcards

1
Q

What is this operator called and what does it do?

??=

E.g.
a ??= 3;

A

Null Assignment operator

If the value to the left is null then it will assign it the value to the right. E.g.

int? a; // = null
a ??= 3;
print(a); // Prints 3

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is this operator called and what does it do?

??

E.g.
print(1 ?? 3);

A

Null Aware operator

It will return the value on the left, however if that value is null then it will return the value on the right.

E.g.
print(1 ?? 3); // Prints ‘1’
print(null ?? 12); // Prints ‘12’

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What is this operator called and what does this operator do?

?.

E.g.
obj?.method()

A

Null Conditional Member Access operator

If the object on the left is null then null will be returned, however if it is not null then the result of the method (or property getter) will be returned.

Use ?. when you want to call a method/getter on an object IFF that object is not null (otherwise, return null).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is this operator called and what does it do?

…?

A

Null Spread operator

Placing … before an expression inside a collection literal unpacks the result of the expression and inserts its elements directly inside the new collection. If the expression is null then it will be ignored.

List lowerNumbers = [1, 2, 3, 4, 5];
List? upperNumbers = null;
List numbers = […lowerNumbers, …?upperNumbers];
numbers.forEach(print); // Prints ‘1 2 3 4 5’

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

4 reasons to use getters and setters…

A
  1. Read-only access
  2. Write only access
  3. Verify on set
  4. Compute a value before set
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is the format of the single-line ternary operator?

A

aBoolean ? isTrue : ifFalse;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is this operator and what does it do?

.. (2 dots)

Also is there a null-safety version?

A

Cascade operator

It perform a sequence of operations on the same object.

E.g.

BigObject fillBigObject(BigObject obj) {
  return obj
    ..anInt = 1
    ..aString = 'String!'
    ..aList = [3.0]
    ..allDone();
}

Note that the return value of each operation is ignored and after all of the operations have completed the cascade will return the original object that is being operated on. In this case… obj.

The null-safety version is ?.. (null-shorting) and it will only perform the cascading operations if the object is not null. You only use it on the first operator and the rest are all normal ones. E.g.

result1
?..doStuff()
..doMoreStuff();

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What are these two operators:

  1. .. (2 dots)
  2. … (3 dots)
A
  1. .. (2 dots) The cascade operator. It’s for chaining multiple operations on the same object. It returns the object itself.
  2. … (3 dots) The Spread operator. It’s for unpacking the result of an expression into a collection literal definition.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

When do we need to use initialiser lists?

A

All final final fields must be initialised in the initialiser list section of a class’ constructor. They can’t even be used in the constructors body until they have been initialised. The initialiser list runs before the constructor’s body.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What is the purpose of assert() calls?

A

To find errors during debugging.

Asserts will not be run during production.

They can also be used to run specific logic during debug builds only. See https://stackoverflow.com/questions/56537718/what-assert-do-in-dart

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How do you lazily initialise a field?

A

Use the late modifier and provide a function call as the return value.

E.g.

class Weather {
  late int _temperature = _readThermometer();
}

Instead of running it as soon as the instance is constructed, it is deferred and run lazily the first time the field is accessed.

The function (in this case _readThermometer) is called only on the first time. This appears to make a lazy initialised field final by nature.

A constructor call can also be used to late initialise objects. e.g.
class Weather {
  late TempSensor _tempSensor = TempSensor();
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Why would you use lazy initialisation?

A

When the initialisation expression is costly and may not be needed.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How can you access ‘this’ when initialising fields?

A

Usually instance field initialisers cannot access ‘this’ because you don’t have access to the new object until all field initialisers have completed. But with a late field, that’s no longer true, so you can access ‘this’, call methods, or access fields on the instance.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

When is it okay to use ‘var’ instead of explicitly declaring the type?

A

When they are local variables in small functions with very little scope. If the function is large enough that the reader must scroll then the full type should be declared instead.

Due to the small scope size, the reader does not have to scroll to where the variable is initialised to see the declared type. The initialisation code will always be visible.

Omitting the type focuses the reader’s attention on the more important name of the variable and its initialised value.

This will be most beneficial when you have long Types cluttering the code. E.g. List>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What does the asterisk mean in async* and sync*?

A

It makes that function a ‘Generator Function’.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What does a ‘Generator Function’ do?

A

It returns a sequence of values.

17
Q

What does a synchronous generator (sync*) function return?

A

An Iterable.

18
Q

What does an asynchronous generator (async*) function return?

A

A Stream.

19
Q

What’s the key difference between sync* and async* generator functions?

A

The calling code has to wait for a sync* generator to finish and return the iterable. An async* generator does not halt the calling code and the returned Stream can be listened to asynchronously.

20
Q

When does a generator function, generate its results?

A

Only when then are requested. Either when the Iterable is iterated over or when the Stream is listened to.

21
Q

What does yield do?

A

It is used to emit values from a generator without returning from the function.

22
Q

What does yield* do?

A

It delegates the call to another generator and after that generator stops producing the values, it resumes generating its own values.

Example…

Stream stream1() async* {
  yield 100;
  yield* stream2(3);
  yield 200;
  yield* stream2(2);
  yield 300;
}
Stream stream2(int input) async* {
  for (int i = input; i >0; i--) {
    yield i;
  }
}
void main() {
  Future fut = stream1().forEach(print);
}

This will print: 100, 3, 2, 1, 200, 2, 1, 300.

Note: You can yourself recursively using this.

23
Q

Two way to create a stream?

A
  1. Create a function marked with async*

2. Using a StreamController.

24
Q

The ‘is’ operator checks if an object is of a certain type. What is the ‘is not’ operator?

A

is!

Note: The ! is after the is and not before.

25
Q

What does this operator do…

?[]

A

This the conditional subscript access operator.

Much like the subscript access operator… [ i ] it is used to access an item in a list. However, this null-safety version will only do so if the list object itself is not null. If it is then null is returned.

26
Q

Error vs Exception

A

Error: An Error object represents a program failure that the programmer should have avoided.

An Exception is intended to convey information to the user about a failure, so that the error can be addressed programmatically. It is intended to be caught, and it should contain useful data fields.

27
Q

In a try/catch block what does the ‘on’ keyword do?

A

Use ‘on’ when you need to specify the exception type.

28
Q

In a try/catch block what does the ‘catch’ keyword do?

A

Use ‘catch’ when your exception handler needs the exception object.

29
Q

In a try/catch block how do you catch everything?

A

You don’t specify any ‘on’.

E.g.

} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}
30
Q

The catch call can take 2 parameters. The first is the Exception itself but what is the 2nd optional argument?

A

The second is the stack trace (a StackTrace object).

31
Q

What is a Dart package?

What is a plugin?

A

Packages have only dart code.

Plugins have dart + native code. E.g. platform plugins for getting device data.

32
Q
When would you use the following parameterized type names?
E
R
K
V
T
S
U
A
E = Element in a collection.
R = Return type.
K = Key in a map.
V = Value in a map.
T, S, U = Any other types, start with T and use S and U to avoid shadowing.
33
Q

Dart generic types are reified, which means that they…

A
...carry their type information around at runtime.
E.g.
var names = [];
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List); // true
34
Q

What does ‘show’ and ‘hide’ do to import statements?

A
hide = Import all except the class/function/variable that you name.
show = Import only the class/function/variable that you name.

Note; You can show/hide multiple things by separating them with a comma.

35
Q

What’s an easy way to wait for multiple Futures to complete before running some other code?

A

await Future.wait(List);