Wednesday, January 9, 2013

Dart Part Access

‹prev | My Chain | next›

I am in the process of rewriting the libraries & parts chapter of Dart for Hipsters and it occurs to me that I do not fully understand the scoping rules for parts. Although I likely will not touch on the specific subject in the chapter, I would, for my own edification, like to know if a part can access the main library and another part.

My conceptual understanding of parts says that yes, parts should be able to access other parts as if they were all defined directly in the same file. This is, in fact, the very purpose (I think) of parts in Dart. Unfortunately, I almost have myself convinced that it will not work—mostly because I have been replacing discussions of the now defunct #source() directive and have myself confused. Let's see what the code says.

I create sum_of_parts.dart with a single function that doubles a number:
library sum_of_parts;
part 'triple_double.dart';
part 'quadruple_triple_double.dart';

double(x) => 2 * x;
This double() function is defined directly in the main library. I have also included two other parts for my "sum_of_parts" library. The first is triple_double.dart, which triples the result of the double() function defined in the main library:
part of sum_of_parts;

triple_double(x) => 3 * double(x);
Using the part of syntax to reciprocate the library's part directive ensures that Dart will consider this to effectively be part of the main sum_of_parts library. Thus, the triple_double() function ought to work. Since they are both parts of the same library, I ought to be able to call one function from the other.

Similarly, if the second part of my simple library, quadruple_triple_double.dart calls the triple_double() function, then it ought to work:
part of sum_of_parts;

quadruple_triple_double(x) => 4 * triple_double(x);
This will work because these "part of" the main library are another way of writing everything in a single file as:
library sum_of_parts;

double(x) => 2 * x;
triple_double(x) => 3 * double(x);
quadruple_triple_double(x) => 4 * triple_double(x);
And this does, in fact work. I write three tests to set my expectation that the three functions will return the expected quadrupling, tripling or doubling:
import 'sum_of_parts.dart' as Parts;

run() {
  group("[main]", (){
    test('can call functions defined directly in library', (){
      expect(Parts.double(3), equals(6));
    });

    test('functions in parts can call functions defined in main library', (){
      expect(Parts.triple_double(3), equals(18));
    });

    test('functions in parts can call functions in other parts', (){
      expect(Parts.quadruple_triple_double(3), equals(72));
    });
  });
}
And this passes:
➜  tests git:(master) ✗ dart test.dart
unittest-suite-wait-for-done
PASS: [main] can call functions defined directly in library
PASS: [main] functions in parts can call functions defined in main library
PASS: [main] functions in parts can call functions in other parts

All 3 tests passed.
And, just as importantly, this passes dart_analyzer's scrutiny:
➜  tests git:(master) ✗ dart_analyzer test.dart 
➜  tests git:(master) ✗ 
Before calling it a night, I try variables as well. I define var one = 1; in the main library. I define var two = 2; in triple_double.dart and var three = 3; in quadruple_triple_double.dart. And in triple_double.dart, I define a function that can use these hard coded integers to answer the eternal question of what is 1 + 2 + 3 + another number?
part of sum_of_parts;

triple_double(x) => 3 * double(x);
var two = 2;

one_plus_two_plus_three_plus(x) => one + two + three + x;
Again, one and three are defined in the main library and another part respectively. I write a test to verify this function as well:
import 'package:unittest/unittest.dart';

import 'sum_of_parts.dart' as Parts;

run() {
  group("[main]", (){
    // ...
    test('parts have access to variables', (){
      expect(Parts.one_plus_two_plus_three_plus(4), equals(10));
    });
  });
}
This too passes:
➜  tests git:(master) ✗ dart_analyzer test.dart
➜  tests git:(master) ✗ dart test.dart         
unittest-suite-wait-for-done
PASS: [main] can call functions defined directly in library
PASS: [main] functions in parts can call functions defined in main library
PASS: [main] functions in parts can call functions in other parts
PASS: [main] parts have access to variables

All 4 tests passed.
Cool beans! It seems that I really do have a good conceptual model of parts. Now I just need to forget I ever knew about #source.


Day #625

No comments:

Post a Comment