<section xmlns="http://docbook.org/ns/docbook"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        version="5.0"
        xml:id="sec-option-declarations">

<title>Option Declarations</title>

<para>An option declaration specifies the name, type and description
of a NixOS configuration option.  It is invalid to define an option
that hasn’t been declared in any module.  An option declaration
generally looks like this:

<programlisting>
options = {
  <replaceable>name</replaceable> = mkOption {
    type = <replaceable>type specification</replaceable>;
    default = <replaceable>default value</replaceable>;
    example = <replaceable>example value</replaceable>;
    description = "<replaceable>Description for use in the NixOS manual.</replaceable>";
  };
};
</programlisting>

</para>

<para>The function <varname>mkOption</varname> accepts the following arguments.

<variablelist>

  <varlistentry>
    <term><varname>type</varname></term>
    <listitem>
      <para>The type of the option (see <xref linkend='sec-option-types' />).
      It may be omitted, but that’s not advisable since it may lead to errors
      that are hard to diagnose.</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><varname>default</varname></term>
    <listitem>
      <para>The default value used if no value is defined by any
      module.  A default is not required; in that case, if the option
      value is never used, an error will be thrown.</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><varname>example</varname></term>
    <listitem>
      <para>An example value that will be shown in the NixOS manual.</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><varname>description</varname></term>
    <listitem>
      <para>A textual description of the option, in DocBook format,
      that will be included in the NixOS manual.</para>
    </listitem>
  </varlistentry>

</variablelist>

</para>

<section xml:id="sec-option-declarations-eot"><title>Extensible Option 
    Types</title>

  <para>Extensible option types is a feature that allow to extend certain types 
    declaration through multiple module files.
    This feature only work with a restricted set of types, namely 
    <literal>enum</literal> and <literal>submodules</literal> and any composed
    forms of them.</para>

  <para>Extensible option types can be used for <literal>enum</literal> options 
    that affects multiple modules, or as an alternative to related 
    <literal>enable</literal> options.</para>

  <para>As an example, we will take the case of display managers. There is a
    central display manager module for generic display manager options and a
    module file per display manager backend (slim, kdm, gdm ...).
  </para>

  <para>There are two approach to this module structure:

  <itemizedlist>
    <listitem><para>Managing the display managers independently by adding an
        enable option to every display manager module backend. (NixOS)</para>
    </listitem>
    <listitem><para>Managing the display managers in the central module by
        adding an option to select which display manager backend to use.</para>
    </listitem>
  </itemizedlist>
  </para>

  <para>Both approachs have problems.</para>
    
  <para>Making backends independent can quickly become hard to manage. For
    display managers, there can be only one enabled at a time, but the type
    system can not enforce this restriction as there is no relation between
    each backend <literal>enable</literal> option. As a result, this restriction
    has to be done explicitely by adding assertions in each display manager
    backend module.</para>

  <para>On the other hand, managing the display managers backends in the
    central module will require to change the central module option every time
    a new backend is added or removed.</para>

  <para>By using extensible option types, it is possible to create a placeholder 
    option in the central module (<xref linkend='ex-option-declaration-eot-service' 
      />), and to extend it in each backend module (<xref 
      linkend='ex-option-declaration-eot-backend-slim' />, <xref 
      linkend='ex-option-declaration-eot-backend-kdm' />).</para>
 
  <para>As a result, <literal>displayManager.enable</literal> option values can
  be added without changing the main service module file and the type system
  automatically enforce that there can only be a single display manager
  enabled.</para>

<example xml:id='ex-option-declaration-eot-service'><title>Extensible type 
    placeholder in the service module</title>
<screen>
services.xserver.displayManager.enable = mkOption {
  description = "Display manager to use";
  type = with types; nullOr (enum [ ]);
};</screen></example>

<example xml:id='ex-option-declaration-eot-backend-slim'><title>Extending 
    <literal>services.xserver.displayManager.enable</literal> in the 
    <literal>slim</literal> module</title>
<screen>
services.xserver.displayManager.enable = mkOption {
  type = with types; nullOr (enum [ "slim" ]);
};</screen></example>

<example xml:id='ex-option-declaration-eot-backend-kdm'><title>Extending 
    <literal>services.foo.backend</literal> in the <literal>kdm</literal> 
    module</title>
<screen>
services.xserver.displayManager.enable = mkOption {
  type = with types; nullOr (enum [ "kdm" ]);
};</screen></example>

<para>The placeholder declaration is a standard <literal>mkOption</literal> 
  declaration, but it is important that extensible option declarations only use 
  the <literal>type</literal> argument.</para>

<para>Extensible option types work with any of the composed variants of 
  <literal>enum</literal> such as 
  <literal>with types; nullOr (enum [ "foo" "bar" ])</literal> 
  or <literal>with types; listOf (enum [ "foo" "bar" ])</literal>.</para>

</section>
</section>