This Week in D May 10, 2015

Welcome to This Week in D! Each week, we'll summarize what's been going on in the D community and write brief advice columns to help you get the most out of the D Programming Language.

The D Programming Language is a general purpose programming language that offers modern convenience, modeling power, and native efficiency with a familiar C-style syntax.

This Week in D has an RSS feed.

This Week in D is edited by Adam D. Ruppe. Contact me with any questions, comments, or contributions.

Statistics

In the community

Community announcements

See more at digitalmars.D.announce.

Significant Forum Discussions

See more at forum.dlang.org and keep up with community blogs at Planet D.

Tip of the week

This week, we'll see how you can combine local imports with function templates to implement optional compile-time dependencies.

Normally, when you import a module, it is required that dmd is able to find it when you build the program:

	import foo; // if foo.d can't be found, the build will fail

There are times, however, when you want to make an import optional or done only on-demand. This allows you to compile a module on its own if you don't need a feature while keeping the feature available if you are willing to use the dependency. The traditional way to accomplish this was to write a helper module:

	module outside_dependency;
	// library code
	class LibraryObject {}
	module your_code;
	// your code here, all self-contained

	class YourObject {}

	// and/or you can define interfaces that are implemented by driver modules
	interface UseLibrary {}
	module your_code_integrated_with_outside_dependency;

	import your_code;
	import outside_dependency;

	// code that integrates your code with the dependency

	void useLibrary(YourObject obj, LibraryObject lo) {}

	// Then, you can call these functions with pseudomember
	// syntax on your object.

	// OR you can implement driver classes

	class YourLibraryUser : UseLibrary {
                  // implement the interface using outside_dependency
	}

These traditional techniques work well and are useful in a variety of situations. The interface and class driver pattern also provides runtime polymorphism, letting you swap out implementations at runtime.

My database.d uses this pattern to provide an optional set of drivers. database.d declares an interface, then optional dependencies, mysql.d, postgres.d, sqlite.d, and mssql.d implement that interface to use C libraries to talk to the actual databases.

However, needing a third connector module or the runtime overhead of interfaces isn't always desirable. You might want a compile-time optional import of a single file, for example, to change a library's core interface based on the availability of a library.

D has two options for this: one is conditional compilation based on the version keyword or a configuration module that declares manifest constants that are inspected with static if. These facilities work similarly to the preprocessor in C. You can read about version here and the module configuration technique in my D Cookbook.

Those techniques work best when you want to change the implementation of a function or do a wholesale replacement of the interface based on compile time switches.

The other option is the trick we'll learn here: use a local import so a function is always available, but its imports are only processed if that function is actually run:

	import bar; // bar is always required if you use this module

	void useFoo()() {
		import foo; // but foo is only required if you actually call useFoo!
	}

Here, useFoo is always part of the public interface, but unless your module's user actually calls useFoo, the import within is not processed, thus making the dependency optional to the module as a whole.

My dom.d uses this technique to handle documents that use character sets other than UTF-8. Character set conversion requires an additional module: charactersets.d. But, if you don't need this, if you know all data you'll feed to dom.d is already UTF-8 encoded, you can avoid downloading the additional charactersets.d file.

It accomplishes this by providing two public functions: parseUtf8, which has no dependencies, and parse()(args...) which imports arsd.characterencodings. Internally, since it knows it is always using utf-8 strings, it uses parseUtf8. Only in places where the character set is unknown will it use the conversion functions.

The entire call tree that may use the charset function are set as templates: that's what the first set of parenthesis are for in parse()(args...). It is a template with zero parameters - no compile-time customization done and the end-user can always call it like a normal function, so they don't need to now it is a template, but it is one, meaning it gets the lazy semantics.

One of the downsides of lazy templates is that the code isn't necessary full compiled unless it is used either. The compiler will ensure the syntax is correct, but not the semantics unless the function is used. Be careful to test actually calling these functions in a library you release to ensure that they do, in fact, successfully build when needed.

As a result, if you just stick to parseUtf8, you can use dom.d alone, without the characterencodings.d dependency.


Find more D tips at the D idioms list or buy my D Cookbook for a more in-depth examination of many D tricks.

If you'd like to submit a tip, email me.

Upcoming events

Learn more about D

To learn more about D and what's happening in D: