Busy Developer's Guide to Dart Ted Neward Neward & Associates - - PowerPoint PPT Presentation
Busy Developer's Guide to Dart Ted Neward Neward & Associates - - PowerPoint PPT Presentation
Busy Developer's Guide to Dart Ted Neward Neward & Associates http://www.tedneward.com | ted@tedneward.com Dart Overview In a nutshell... Dart Overview Dart "Dart is a class-based, single-inheritance, pure object-oriented
Dart Overview
In a nutshell...
Dart Overview
Dart
"Dart is a class-based, single-inheritance, pure object-oriented programming language. Dart is optionally typed and supports reified generics. The runtime type of every object is represented as an instance of class Type which can be
- btained by calling the getter runtimeType declared in class
Object, the root of the Dart class hierarchy. "Dart programs may be statically checked. The static checker will report some violations of the type rules, but such violations do not abort compilation or preclude execution. "Dart programs may be executed in one of two modes: production mode or checked mode. In production mode, static type annotations have absolutely no effect on execution with the exception of reflection and structural type tests. In checked mode, assignments are dynamically checked, and certain violations of the type system raise exceptions at run time."
Dart Overview
Dart
– developed at Google – developed because "Google cares about the Web"
specifically built for Google's own use
– ECMA standard (ECMA-408)
4th Edition (December 2015)
– targets multiple contexts
- command-line applications
these run in the DartVM
- front-end web development
these will typically transpile to Javascript
- iOS/Android applications
makes use of Flutter (https://flutter.io)
Objectives
What are we going to do today?
– examine the Dart ecosystem – learn (a bit) about the Dart language
Getting Started
From Zero to Hello World
Getting Started
Hello, Dart
– easiest way to play with Dart is with DartPad
https://dartpad.dartlang.org/33706e19df021e52d98c
– ... but that's not what we're after!
Getting Started
Requirements to install Dart
– Windows, Mac or Linux OS
that's pretty much it
Getting Started
Installing on Windows
– Chocolatey
choco install dart-sdk -version {version} choco install dartium -version {version}
– MSI installer (community-sponsored)
Getting Started
Installing on Mac
– Homebrew
brew tap dart-lang/dart brew install dart --with-content-shell --with-dartium
Getting Started
Installing on Linux
$ sudo apt-get update $ sudo apt-get install apt-transport-https # Get the Google Linux package signing key. $ sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' # Set up the location of the stable repository. $ sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_st able.list > /etc/apt/sources.list.d/dart_stable.list' $ sudo apt-get update
Source: https://www.dartlang.org/install/linux
Getting Started
Installing manually
– Download zip file
https://www.dartlang.org/install/archive
– Unzip manually, set PATHs, etc
Getting Started
Hello, Dart
// Define a function. printNumber(num aNumber) { print('The number is $aNumber.'); // Print to the console. } // This is where the app starts executing. main() { print("Hello, Dart"); // Print to the console. var number = 42; // Declare and initialize a variable. printNumber(number); // Call a function. } $ dart hello.dart Hello, Dart The number is 42.
Getting Started
Hello, Dart
– execution begins in main() – print() writes to the console
which is always present, context-dependent location
Modes
Dart has two modes: production and checked
– Checked is "developer mode"
- verify static types
- execute assert() statements
– Production is... well, duh
- ignores type declarations
- ignores assert() statements
- optimized for speed
Basic Syntax
Basic Syntax
Source code
– Dart (like most languages) is a text-based language – Source code is in the common subset of Unicode supported by most languages
- effectively, ASCII
- note that this is not specifically described anywhere; could
expand to full Unicode at some point
– Comments are either // or /* */ -style comments
- // -- to end-of-line
- /* */ -- multiline comment using (nestable) open/close pairs
- /// -- documentation comment to end-of-line
- /** */ -- multiline documentation comment using open/close
pairs
Basic Syntax
Identifiers
– C-style Identifiers
starts with letter or _, followed by letters/numbers/_
– reserved words cannot be used as Identifiers
abstract as assert async async* await break case catch class const continue default deferred do dynamic else enum export external extends factory false final finally for get if implements import in is library new null operator part rethrow return set static super switch sync* this throw true try typedef var void while with yield yield*
Basic Syntax
Format
– made up of statements and expressions
- expressions yield values
- statements do not
– statements/expressions must be terminated by semicolon
in the spirit of C, C++, Java, C#, ...
Primitive Types
The atoms of the type system
Primitive Types
Important concepts
– Everything you can place in a variable is an object – Every object is an instance of a class
numbers, functions, and null are objects
– All objects inherit from the Object class – Dart supports top-level variables (globals)
Primitive Types
Variables
– declared using either "var name" or "{type} name"
in the spirit of C, C++, Java, C#, ...
– mutable by default; use "final" or "const" to make immutable
- final means only-assigned-once
- const must be a compile-time constant
– uninitialized variables initialize to null
Primitive Types
Numbers ("num")
– num type supports most expected operations
- "+", "-", "*", "/", "%"
- abs(), floor(), ceil(), ...
– "int" (signed, -2^53 to 2^53) is subtype of "num"
- supports bitwise shift ("<<" ">>", "&", "|") operators
– "double" (64-bit IEEE 754 floating-point) is also subtype of "num"
Primitive Types
Strings ("string")
– sequence of UTF-16 code units – literals denoted by single-tick or double-tick pairs
- backslash can denote special characters ("\n", "\t", etc)
- backslash-escaping turned off by "raw" strings ("r"-prefixed
string)
– strings also support $-denoted string interpolation – strings concatenate using "+" or simply being adjacent to
- ne another
– strings support "multi-line" strings using triple-quoted marks
Types
Primitive Types
var x = 1; var y = 1.1; var exponents = 1.42e5; var one = int.parse('1'); assert(one == 1); var oneStr = 1.toString(); assert(1 == (int.parse(1.toString()))); var s1 = 'Hello ' 'world' " from Dart"; print(s1); var s2 = ''' Multi- line strings '''; print (s2); var s3 = 'string interpolation'; var s4 = 'Dart has $s3, which is handy'; // Dart has string interpolation, which is handy
Primitive Types
Booleans ("bool")
– only two possible values, "true" and "false" – in boolean expressions, only "true" is true
no ECMAScript-like "truthy"/"falsy" implicit conversions; generates an exception in checked mode
Types
Type-checking can avoid common errors
var name ='Bob'; if (name) { print('JavaScript says you have a name!'); // dart --checked will throw an exception, because // 'name' is not a boolean type } if (1) { print('JavaScript prints this line because it thinks 1 is true.'); } else { print('Dart in production mode prints this line.'); // However, in checked mode, if (1) throws an exception. }
Primitive Types
Lists (arrays)
– denoted using square-brackets ("[]") – literals use commas to separate values
"const" before the literal makes it a compile-time constant list
– square-brackets used to access individual elements by position – zero-based indexing – .length returns the length of the list – lists are mutable by default
it is possible to create immutable lists
Primitive Types
Maps (dictionaries)
– denoted using curly-brackets ("{}") – literals use commas to separate colon-associated pairs of values
"const" before the literal makes it a compile-time constant map
– square-brackets used to access individual elements by key
missing keys yield null
– .length returns the length of the list of pairs – maps are mutable by default
Primitive Types
Runes (UTF-32 code points)
– referenced using "\uXXXX" syntax (where XXXX is 4-digit hex) – for larger than 4-digit hex, surround the value with {}
Primitive Types
Symbols
– represents an operator or identifier declared in a Dart program
invaluable for APIs that refer to identifiers by name; minification changes identifier names but not identifier symbols
– symbol literals use "#"-prefixed literal name – compile-time constants – most often used in conjunction with dart:mirrors- reflection library
Primitive Types
Functions
– functions are objects of type Function – this allows functions to be passed, stored, etc
enables a certain subset of functional programming style
Primitive Types
Enumerations (enums)
– use "enum" keyword; integer-backing – access the integer backing value using ".index" – get a full list of the enum values using static "values" constant – when used in switch statements, compiler checks for full- range evaluation
Primitive Types
dynamic
– "placeholder" type designed to allow for optional typing
essentially compiler will do no type-checking around a dynamic-declaration
Control Flow
Ifs, ands, whiles and fors
Control Flow
If/else
– standard C-style "if" construct
else is optional, else if chains tests, etc
– must be boolean test expression
Control Flow
If
if (isRaining()) { print("Welcome to Seattle"); } else if (isSnowing()) { print("Welcome to... uh... the US"); } else { print("Welcome to Las Vegas"); }
Control Flow
While and do/while
– standard C-style "loop until false" constructs – must be boolean test expression
Control Flow
While and do/while
while (isRaining()) { print("Stay indoors"); } do { print("Writing code while I stay indoors"); } while(isRaining());
Control Flow
For (three-expression style)
– pretty much everything the C-style for does
Control Flow
For-in (iteration style)
– any Iterable object supports for-in – any change to the collection breaks the iteration – Iterable objects also support forEach() (preferred)
Control Flow
Switch/case
– standard C-style "switch" block – each non-empty "case" must terminate with "break"
- empty case statements fall through
- alternatively, use "continue {label}" to force fall-through
– case matches must be compile-time constants
Control Flow
Assert
– accept boolean condition, then generate exception if false – only operate as intended in checked mode
in production mode, they turn into a no-op
Control Flow
Try/catch/throw
– "throw new {object}" immediately begins walk up call stack
any arbitrary object may be thrown
– "try" { body } establishes range of guarded code – "on {type} { body }" executes body on {type} exceptions – "catch(ex) { body }" is the catch-all handler – "finally { body }" always executes
Operators
Doing 'x' to 'a' and 'b'
Operators
Dart supports full range of operators
– mathematical ( ++ -- + - * / % ~/ )
including math-assignment ( = += -= *= /= %= ~/= ) ~/ ~/= are "divide with integer result"
– bitwise ( << >> & ^ | )
including bitwise-assign ( <<= >>= ^= |= &= )
– relational ( == != && || <= >= < > )
including conditional ( t : a ? b )
– type-test ( as is is! ) – object-related ( () [] . ?. .. ) – NOTE: operator implementation resolution use the left- hand operand
ex: aVector + aPoint will use aVector's implementation of +
Operators
Equality tests
– == != do an equality comparison
meaning, compare the contents
– == returns null if lhs or rhs is null – to do an identity comparison, use the identical() function
Operators
Null-safe operators
– ?? is the null-test operator
a ?? b returns a if a != null, else b
– ?. is the null-safe resolution operator
a?.b yields b returns b if a != null, else null
Functions
Capturing logic
Functions
Functions: named blocks of code
– C-style syntactic approach
return-type function-name(param-type param-name, ...) { body }
– types are encouraged, but not mandatory
function-name(param-name, ...) { body }
– body can be elided if it is a simple expression-return
function-name(param-name, ...) => expression
Functions
Simple functions
void printNumber(num number, num times) { print('The number you passed is $number.'); } void printAnotherNumber(number) => print('Here is $number.'); void main() { var printIt = (number) => print('Yet again, $number.'); printNumber(27); printAnotherNumber(27); printIt(27); }
Functions
Parameters come in two flavors: required and
- ptional
– required come first – optional parameters can be either positional or named (not both)
- named defined using {}-denoted enclosing parameter list
- positional defined using []-denoted parameter list
- optional named parameters invoked using name: value lists
Functions
Optional parameters can have default values attached
– use "=" syntax after param-name in list – without default value, optional parameters (if not passed) are null
Functions
Optional named and positional parameters
void doSomething({bool printIt: false, bool logIt: true}) { if (printIt) { print("We're printing something"); } if (logIt) { print("We're logging something"); } } void logIt(String msg, [String language: 'English']) { print("We're logging $msg in $language."); } void main() { doSomething(printIt: true, logIt: false); logIt("Hello, world!"); }
Functions
Functions are first-class objects
– passed as parameters, stored as variables, etc
all functions are of type "function"
– "ordinary" objects can also be made callable
implement a call() function in the class
– Function types can be expressed using "typedef"
typedef int Compare(Object a, Object b); "Compare" is now a function type that can be used/compared/etc
Functions
First-class functions
bool shortName(string name) => name.length < 10; bool printName(string name) { print("$name is easy to vote for."); } void main(List<string> args) { List<string> candidates = [ "Barack Obama", "Joe Biden", "John McCain", "Sarah Palin", "Mickey Mouse", "Goofy" ]; var shortList = candidates.where(shortName); shortList.forEach(printName); }
Functions
Functions can be lexically nested
– nested functions are no different than non-nested functions – except that they cannot be seen from outside lexical scope
in other words, just as with any other variable
– aids in implementation-hiding
Functions
Anonymous functions (lambdas, closures, etc)
– uses "fat arrow" syntax
(param-list) => { statements }; (param-list) => statement;
– types may be specified to parameter list (optional) – access to surrounding lexical scope – closure capture is by-value, not by-reference
value of the variable enclosed is captured at time of closure creation
Functions
Closures
// "function" is the return type, not a keyword! function makeAdder(num addBy) { // Not seen outside of makeAdder() adder(num i) { return addBy + i; } return adder; } void main() { var addBy2 = makeAdder(2); assert(add2(3) == 5); var addBy4 = makeAdder(4); assert(add4(3) == 7); // Closures capture by-value not by-reference var callbacks = []; for (var i = 0; i < 2; i++) { callbacks.add(() => print(i)); } callbacks.forEach((c) => c()); // prints 0, 1; in JavaScript, this would be 2, 2 }
Classes
Defining types in Dart
Classes
Classes define types
– all objects are instances of a class – class keyword begins definition – classes have members
- variables
- constructors
- methods (including getters/setters)
- operators
– members can also be static
- variables
- methods
Classes
Class syntax
– access is either public or private
- denoted by presence/absence of leading _
- "foo" would be public
- "_foo" would be private
– "this" keyword refers to instance – "." is access operator to obtain members
Classes
Cascade operator ("..")
– used to reference a previous object – essentially another way of doing "fluent chaining"
typically useful for setters or non-return-capturing methods
– cascade as many times as desired/necessary
Classes
Instance variables
– "{type} {identifier}" defines instance variable – implicitly defines getter and setter
setter only for mutable (non-final, non-const) variables
– initialized to null if not explicitly initialized
Classes
Simple class declaration/use
class Person { // These are all public String lastName = "(None)"; String firstName; // initially null // These are private (_-prefixed) num _age = 0; Person(this.firstName, this.lastName); Person.singular(String firstName) { this.firstName = firstName; } } void speakers() { Person speaker = new Person("Ted", "Neward"); Person theDude = new Person.singular("The Dude"); speaker.firstName = "The Dude"; }
Classes
Constructors
– blocks of code to initialize objects before use – no return type, uses same name as class – if no constructor is declared, default (no-arg) constructor is synthesized – "simple constructors" are constructors that just assign params to member variables
- use "this.{member}" in parameter list to match params to
members
- these assignments happen before the body of the
constructor runs
Classes
Chaining constructors
class Point { num x; num y; Point(this.x, this.y); // Chained constructor Point.alongXAxis(num x) : this(x, 0); }
Classes
Named constructors
– "named constructors" provide additional constructors or clarity
"{Classname}.{identifier}(param-list) { body }"
– used exactly the same way from client code – syntactically similar (identical) to static methods in other languages
Classes
Initializer lists
– defined between constructor parameter list and actual body – serves to allow easy member initialization from parameters – initializer lists execute prior to constructor body
very handy for initializing final-declared members
Classes
Factories are constructors of a sort
– they return instances of the type
but not always new instances
– always invoked using "new"
in other words, client never knows the difference
Classes
Factories
class OverdoneDemo { final String name; static final OverdoneDemo _instance = new OverdoneDemo._internal("Singleton!"); OverdoneDemo._internal(this.name); factory OverdoneDemo() { return _instance; } } void overdone() { var od = new OverdoneDemo(); print(od.name); print(new OverdoneDemo().name); print(new OverdoneDemo().name); }
Classes
Methods
– functions defined on the class – can be either instance or static
- instance have lexical access to "this" by default
- static have lexical access to static members by default
– can be abstract by leaving out method body (terminate with semicolon)
non-abstract classes can have abstract methods
Classes
Properties ("getters and setters")
– each instance variable already has an implicit getter/setter – use "get"/"set" to implement additional Properties
typically these will use "shortcut" function/method syntax
Classes
Properties
class Rectangle { num left; num top; num width; num height; Rectangle(this.left, this.top, this.width, this.height); num get right => left + width; set right(num value) => left = value - width; num get bottom => top + bottom; set bottom(num value) => top = value - height; }
Classes
Operator overriding
– finite/limited set of operators available for overriding
< > <= >= + - / ~/ * % | ^ & << >> [] []= ~ ==
– define a non-static method using "operator (op)" as the name – Dart leaves it up to the developer to make common-sense decisions here
Classes
Operators
class Vector { final int x; final int y; const Vector(this.x, this.y); Vector operator +(Vector v) { return new Vector(x + v.x, y + v.y); } Vector operator -(Vector v) { return new Vector(x - v.x, y - v.y); } } main() { final v = new Vector(2, 3); final w = new Vector(2, 3); assert((v+w).x == 4 && (v+w).y == 6); }
Inheritance
Implementation reuse via inheritance
Inheritance
Implementation inheritance
– single base – use "extends" to denote superclass – use "super" to refere to superclass – instance methods, getters, setters are overridable
prefer use of @override to allow compiler verification
– note Object.noSuchMethod()
this is invoked whenever a member is not found during invocation
Inheritance
Interfaces
class TV { void turnOn() { _illuminateDisplay(); _activateIRSensor(); } } class SmartTV extends TV { @override void turnOn() { super.turnOn(); _bootNetworkInterface(); _initializeMemory(); _upgradeApps(); } }
Inheritance
Interfaces
– every class implicitly defines its own interface – classes can "implements" a class and get the interface
but no implementation
– all members are defined by the interface
but not always visible to subclasses
Inheritance
Interfaces
class ThoughtLeader { String _name; // part of the interface, but not always visible ThoughtLeader(this._name); // not part of the interface String greet(who) => "Hello, $who. I am $_name, a Thought Leader."; } class Imposter implements ThoughtLeader { final _name = ""; // required -- part of the interface String greet(who) => "Hello, $who. Don't you know who I am?"; }
Inheritance
Mixins
– permit code reuse from classes without establishing IS-A relationship – to implement a mixin, create a class that...
- extends Object
- declares no constructors
- has no class to super
Inheritance
Mixins
abstract class Musical { bool canPlayPiano = false; bool canCompose = false; bool canConduct = false; void entertainMe() { if (canPlayPiano) { print("playig piano"); } else if (canConduct) { print("waving hands"); } else { print("humming"); } } } class Musician extends Object with Musical { } class Maestro extends Person with Musical, Aggressive, Demented { Maestro(String maestroName) { super.singular(maestroName); canConduct = true; } }
Generics
Your favorite reusable quote here
Generics
Dart supports parametric polymorphism
– aka "templates" or "generics" – type-replacement of type-parameter from defintion-time
restrict type parameter via "extends" clause in declaration
– angle-bracketed notation (a la Java, C++, C#, etc) – reified types
type-parameter accessible at runtime (even in production mode)
Generics
Collection literals can be type-parameterized
– place the type-parameter in angle-brackets before the actual literal – this will define the types explicitly in otherwise-implicit scenarios
Generics
Collection literals
void main() { var bowlingLeague = <String>["Walter", "Donny", "The Dude"]; var bowlingScores = <String, int>{ "Walter":'198', "Donny":'196', "The Dude":'217' }; var names = new List<String>(); // same as bowlingLeague var scores = new Map<String,int>(); // bowlingScores var uniqueNames = new Set<String>.from(bowlingLeage); print(uniqueNames is Set<String>); // true }
Generics
Generic functions
– methods/functions can have type parameters as well – place angle-bracketed type-parameter list immediately after name
Asynchrony
Walking and chewing gum at the same time (in Dart)
Asynchrony
Async/await
– Dart supports asychrony through async/await keywords
and Future and Stream objects
– for-in can be used with Stream objects
prefix the "for" with "await"
Metadata
Providing data about types in Dart
Metadata
Dart supports metadata through annotations
– @-prefixed class instances – accessible via reflection – custom annotation types possible
simple class
Libraries
Using/creating reusable bodies of code in Dart
Libraries
Libraries are APIs and a unit of privacy
– every Dart app is a library – libraries can be distributed using "pub" (package manager)
Libraries
Import
– import specifies how a namespace from one library is used in the scope of another library
"import 'dart:html'"
– argument to import is a URI specifying the library
- "dart:" is a special scheme for Dart built-in libraries
- "package:" scheme refers to package manager-managed
libraries
- otherwise, a file system path
– imports can define a prefix for all names in the library
"import 'package:lib2/lib2.dart' as lib2;"
– selectively import symbols using "show"
"import 'package:foo/hello.dart' show foo;"
– selectively exclude symbols using "hide"
"import 'package:foo/hello.dart' hide foo;"
Libraries
Deferred import
– libraries can be lazily loaded (deferred) until required – import using "deferred as"
"import 'package:deferred/hello.dart' deferred as hello;"
– then load-on-demand using loadLibrary()
this returns a Future
Libraries
Creating libraries
– libraries consist of multiple things
- code units
- manifest (pubspec.yaml)
– Dart has strong recommendations about file organization
"strong" meaning "some are requirements"
Libraries
Library organization
– root directory contains pubspec.yaml (manifest) – root directory contains "lib"
- by convention, exported code lives in "lib"
- by convention, implementation code lives in "lib/src"
– root will often have other directories
- example
- test
- tool (library-private-use tools)
- bin (public-use tools)
Libraries
pubspec.yaml
– text file (YAML format) describing the library – name: (required) – version: (required for pub.dartlang.org) – description: (required for pub.dartlang.org) – author or authors: (optional) – homepage: (optional) – documentation: (optional)
Libraries
pubspec.yaml
– dependencies: – dev_dependencies: – dependency_overrides: used to override dependencies – environment: configure version of Dart SDK used – executables: puts package executables on the path – transformers: configures code transformers
Resources
Where to find out more
Resources
Resources on Dart
– Website:
http://www.dartlang.org
– Specification:
- https://www.dartlang.org/docs/spec/latest/dart-language-
specification.html
- ECMA 408 (https://www.ecma-
international.org/publications/standards/Ecma-408.htm)
– Tutorials:
https://www.dartlang.org/docs/tutorials/
Credentials
Who is this guy?
– Principal -- Neward & Associates – Director, Smartsheet.com
- Developer Relations
- Solutions Engineering