kotlin_dart 0.4.0

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 60

kotlin.dart #

Pub

This project is a port of Kotlins Kotlin Standard library for Dart/Flutter projects. It's a useful addition to dart:core and includes collections (KtList, KtMap, KtSet) as well as and other packages which can improve every Dart/Flutter app.

Motivation #

Dart's dart:core package provides basic building blocks. But sometimes they are too low leven and not as straight-forward as Kotlins kotlin-stdlib.

Here are a few examples what this project offers: (click to expand)

Immutable collections by default

dart:core collections

Dart's List is mutable by default. The immutable List.unmodifiable is the same type but the mutation methods throw at runtime.

final dartList = [1, 2, 3];
dartList.add(4); // mutation is by default possible
assert(dartList.length == 4);

final immutableDartList = List.unmodifiable(dartList);
immutableDartList.add(5); // throws: Unsupported operation: Cannot add to an unmodifiable list

Dart's mutable List is undistinguishable from an immutable List which might cause errors.

void addDevice(List<Widget> widgets, Device device) {
  // no way to check whether widgets is mutable or not
  // add might or might now throw
  widgets.add(_deviceRow());
  widgets.add(Divider(height: 1.0));
}

kotlin.dart collections

KtList and KtMutableList are two different Types. KtList is immutable by default and has no mutation methods (such as add). Methods like map((T)->R) or plusElement(T) return a new KtList leaving the old one unmodified.

final ktList = listOf(1, 2, 3);
// The method 'add' isn't defined for the class 'KtList<int>'.
ktList.add(4); // compilation error
       ^^^

// Adding an item returns a new KtList
final mutatedList = ktList.plusElement(4);
assert(ktList.size == 3);
assert(mutatedList.size == 4);

KtMutableList offers mutation methods where the content of that collection can be actually mutated. I.e. with remove(T) or add(T);

// KtMutableList allow mutation
final mutableKtList = mutableListOf(1, 2, 3);
mutableKtList.add(4); // works!
assert(mutableKtList.size == 4);

All collection types has mutable counterparts: |Immutable|Mutable| |---|---| |KtList | KtMutableList | |KtSet | KtMutableSet, KtHashSet, KtLinkedSet | |KtMap | KtMutableMap, KtHashMap, KtLinkedMap | |KtCollection | KtMutableCollection and all the above | |KtIterable | KtMutableIterable and all the above |

Deep equals

dart:core collections

Dart's List works like a Array in Java. Equals doesn't compare the items, equals only checks the identity. To compare the contents you have to use helper methods methods from 'package:collection/collection.dart'.

// Comparing two Dart Lists works only by identity
final a = [1, 2, 3, 4];
final b = [1, 2, 3, 4];
print(a == b); // false, huh?

// content based comparisons require unnecessary glue code
Function listEq = const ListEquality().equals;
print(listEq(a, b)); // true

// MapEquality isn't deep by default
final x = {1: ["a", "b", "c"], 2: ["xx", "yy", "zz"]};
final y = {1: ["a", "b", "c"], 2: ["xx", "yy", "zz"]};
Function mapEq = const MapEquality().equals;
print(mapEq(x, y)); // false, wtf?!

Function deepEq = const DeepCollectionEquality().equals;
print(deepEq(x, y)); // true, finally

kotlin.dart collections

KtList and all other collection types implement equals by deeply comparing all items.

final a = listOf(1, 2, 3, 4);
final b = listOf(1, 2, 3, 4);
print(a == b); // true, as expected

final x = mapFrom({1: listOf("a", "b", "c"), 2: listOf("xx", "yy", "zz")});
final y = mapFrom({1: listOf("a", "b", "c"), 2: listOf("xx", "yy", "zz")});
print(x == y); // deep equals by default
Common methods

Some of Dart's method names feel unfamiliar. That's because modern languages and frameworks (Kotlin, Swift, TypeScript, ReactiveExtensions) kind of agreed on naming methods when it comes to collections. This makes it easy to switch platforms and discuss implementations with coworkers working with a different language.

expand -> flatMap #

final dList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
final kList = listOf(listOf(1, 2, 3), listOf(4, 5, 6), listOf(7, 8, 9));

// dart:core
final dFlat = dList.expand((l) => l).toList();
print(dFlat); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// kotlin.dart
final kFlat = kList.flatMap((l) => l);
print(kFlat); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

where -> filter #

final dNames = ["Chet", "Tor", "Romain", "Jake", "Dianne"];
final kNames = listFrom(dNames);

// dart:core
final dShortNames = dNames.where((name) => name.length <= 4).toList();
print(dShortNames); // [Chet, Tor, Jake]

// kotlin.dart
final kShortNames = kNames.filter((name) => name.length <= 4);
print(kShortNames); // [Chet, Tor, Jake]

firstWhere -> first, firstOrNull #

final dNames = ["Chet", "Tor", "Romain", "Jake", "Dianne"];
final kNames = listFrom(dNames);

// dart:core
dNames.firstWhere((name) => name.contains("k")); // Jake
dNames.firstWhere((name) => name.contains("x"), orElse: () => null); // null
dNames.firstWhere((name) => name.contains("x"), orElse: () => "Nobody"); // Nobody

// kotlin.dart
kNames.first((name) => name.contains("k")); // Jake
kNames.firstOrNull((name) => name.contains("x")); // null
kNames.firstOrNull((name) => name.contains("x")) ?? "Nobody"; // Nobody

Packages #

annotation #

import 'package:kotlin_dart/annotation.dart';

Annotations such as @nullable or @nonNull giving hints about method return and argument types

collection #

import 'package:kotlin_dart/collection.dart';

Collection types, such as KtIterable, KtCollection, KtList, KtSet, KtMap with over 150 methods as well as related top-level functions. The collections are immutable by default but offer a mutable counterpart i.e. KtMutableList.

Planned #

Planned modules for the future are async, tuples, comparison, range, sequence, text

License #

Copyright 2019 Pascal Welsch

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

0.4.0 (unreleased) #

diff v0.3.0...master

0.3.0 #

diff v0.2.0...v0.3.0

Summary #

This release of Kollection fully covers the project with unit tests, from 52% to 99% 🎉. By doing that bugs where discovered and fixed.

Because Dart doesn't support non-nullable types yet, this update manually checks all method arguments at runtime. Passing null in any method will throw ArgumentError unless documented otherwise.

Behavior changes #

  • #36 All method arguments are now validated for nullability. If a argument isn't documented as "nullable" the method will throw ArgumentError (when asserts are enabled)
  • #51, #46 KIterable<T>.associateWithTo, Kiterable<T>.filterTo, KIterable<T>.filterIndexedTo, KIterable<T>.filterNotTo, KIterable<T>.filterNotNullTo , KIterable<T>.groupByTo ,KMap<T>.mapKeysTo ,KMap<T>.mapValuesTo, KIterable.toCollection did not compile when called directly due to dart-lang/sdk/issues/35518. The type of destination of those methods has been changed to a dynamic type (i.e. KMutableList<T> -> KMutableList<dynamic>). Those methods will now be checked at runtime. This has one advantage: It allows to pass in contravariant types.
final KIterable<int> iterable = listOf([4, 25, -12, 10]);
final result = mutableListOf<num>(); // covariant!
final filtered = iterable.filterIndexedTo(result, (i, it) => it < 10);
expect(identical(result, filtered), isTrue);
expect(result, listOf([4, -12]));
  • #56 KMutableEntry.setValue now throws UnimplementedError because of bug #55. It anyways never worked.
  • #58 KSet doesn't allow mutation of its elements with via set getter. It is now really immutable.

API changes #

Bug fixes #

Documentation changes #

  • #57 Document hashSetOf and linkedSetOf
  • #19 KIterable.any document return value when called without predicate
  • #51 Document expected type of now dynamically typed KIterable<T>.associateWithTo, Kiterable<T>.filterTo, KIterable<T>.filterIndexedTo, KIterable<T>.filterNotTo, KIterable<T>.filterNotNullTo , KIterable<T>.groupByTo ,KMap<T>.mapKeysTo ,KMap<T>.mapValuesTo, KIterable.toCollection

Other changes #

0.2.0 #

diff v0.1.0...v0.2.0

Behavior change #

  • #6 Breaking: KMutableIterator.remove now throws UnimplementedError because of bug #5

API changes #

  • #1 Add Set<T> get set returning the internal dart set
  • #1 Add Map<K, V> get map returning the intenral dart set
  • #7 Add KMap.toMap and KMap.toMutableMap
  • #8 Add KMap.isNotEmpty
  • 3e3228e Add KMap.toString()
  • #9 Add Map.plus, Map.minus and operator +(KMap<K, V> map), operator -(K key)
  • #12 Remove const constructors from collection interfaces
  • #13 Remove default implementations from collection interfaces

Documentation changes #

  • #15 Add documentation for compareBy and compareByDescending

Other changes #

  • #2 Travis CI #2
  • #3, #4 Code coverage
  • #10 Test KMutableList.fill
  • #11 Test KPair, KTriple
  • #14 Test Exceptions
  • #15 Test Comparators naturalOrder(), reverseOrder()
  • #15 Test reverse(Comparator) util function
  • 6dd0d85 Reformatted with dartfmt (80 chars)

0.1.0 #

Initial release for

  • KList/KMutableList
  • KSet/KMutableSet
  • KMap/KMutableMap

with tons of extensions waiting for you to use them!

example/main.dart

import 'package:kotlin_dart/kotlin.dart';

void main() {
  /**
   * Lists
   */
  final mapped = listOf(1, 2, 3, 4).map((it) => ">$it<");
  print(mapped); // [>1<, >2<, >3<, >4<]

  final flatMapped = listOf(1, 2, 3, 4).flatMap((it) => listOf(it * 2, it * 3));
  print(flatMapped); // [2, 3, 4, 6, 6, 9, 8, 12]

  final filtered = flatMapped.filter((it) => it % 3 == 0);
  print(filtered); // [3, 6, 6, 9, 12]

  final distinct = listFrom([1, 2, 3, 1, 2, 3]).distinct();
  print(distinct); //[1, 2, 3]

  /**
   * Better equals
   */
  final kListEquals = listOf(12, 9, 6, 3) == listOf(12, 9, 6, 3);
  print(kListEquals); // true

  final dartListEquals = [12, 9, 6, 3] == [12, 9, 6, 3];
  print(dartListEquals); // false

  final kMapEquals = mapFrom({1: "Bulbasaur", 2: "Ivysaur"}) ==
      mapFrom({1: "Bulbasaur", 2: "Ivysaur"});
  print(kMapEquals); // true

  final dartMapEquals =
      {1: "Bulbasaur", 2: "Ivysaur"} == {1: "Bulbasaur", 2: "Ivysaur"};
  print(dartMapEquals); // false

  /**
   * Sets
   */
  print(setOf(1, 2, 3, 1, 2, 3)); // [1, 2, 3]

  /**
   * Maps
   */
  final pokemon = mutableMapFrom({
    1: "Bulbasaur",
    2: "Ivysaur",
  });
  pokemon[1] = "Ditto";
  print(pokemon); // {1=Ditto, 2=Ivysaur}

  /**
   * Tons of useful operators which *should* be part of the dart std lib
   */
  final numbers = listOf(1, 2, 3, 4);
  print(numbers.sum()); // 10

  final numbers5 = listOf(1, 2, 3, 4).sortedDescending();
  print(numbers5); // [4, 3, 2, 1]

  final beatles = setOf("John", "Paul", "George", "Ringo");
  print(beatles); // [John, Paul, George, Ringo]
  print(beatles.joinToString(
      separator: "/",
      transform: (it) => it.toUpperCase())); // JOHN/PAUL/GEORGE/RINGO

  final grouped = beatles.groupBy((it) => it.length);
  print(grouped); // {4=[John, Paul], 6=[George], 5=[Ringo]}
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  kotlin_dart: ^0.4.0

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:kotlin_dart/annotation.dart';
import 'package:kotlin_dart/collection.dart';
import 'package:kotlin_dart/exception.dart';
import 'package:kotlin_dart/kotlin.dart';
  
Version Uploaded Documentation Archive
0.4.3 Jan 11, 2019 Go to the documentation of kotlin_dart 0.4.3 Download kotlin_dart 0.4.3 archive
0.4.2 Jan 9, 2019 Go to the documentation of kotlin_dart 0.4.2 Download kotlin_dart 0.4.2 archive
0.4.1 Jan 9, 2019 Go to the documentation of kotlin_dart 0.4.1 Download kotlin_dart 0.4.1 archive
0.4.0 Jan 9, 2019 Go to the documentation of kotlin_dart 0.4.0 Download kotlin_dart 0.4.0 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
26
Health:
Code health derived from static analysis. [more]
97
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
91
Overall:
Weighted score of the above. [more]
60
Learn more about scoring.

We analyzed this package on Feb 14, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.1.0
  • pana: 0.12.13

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in libraries.

Health suggestions

Fix lib/src/collection/extension/iterable_extension_mixin.dart. (-1.99 points)

Analysis of lib/src/collection/extension/iterable_extension_mixin.dart reported 4 hints:

line 705 col 9: Don't explicitly initialize variables to null.

line 752 col 9: Don't explicitly initialize variables to null.

line 1141 col 9: Don't explicitly initialize variables to null.

line 1170 col 9: Don't explicitly initialize variables to null.

Fix lib/src/collection/extension/list_extension_mixin.dart. (-1 points)

Analysis of lib/src/collection/extension/list_extension_mixin.dart reported 2 hints:

line 190 col 9: Don't explicitly initialize variables to null.

line 218 col 9: Don't explicitly initialize variables to null.

Maintenance suggestions

The description is too long. (-9 points)

Search engines display only the first part of the description. Try to keep the value of the description field in your package's pubspec.yaml file between 60 and 180 characters.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0 <3.0.0
Dev dependencies
test ^1.0.0