Modules: importing and renaming

Importing a module allows you to specify:

  • what to use from the imported module,
  • what do with their names, and
  • what to re-export

Importing names "as is"

If the module is imported unprefixed, all of the names imported from the module will be used as-is. For instance, suppose "mymodule.xmd" exports two functions, a stream-returning function called mymodule-version-string and an integer-returning function next:

    module
    export stream function mymodule-version-string as
      return 'Mymodule version 1.0'
  
     global integer count initial {1}
     export integer function next as
        set count to (count * "ABCDEF97" base 16) shift -1
        return count

The module can be imported, allowing calls to the functions next and mymodule-version-string.

  import "mymodule.xmd" unprefixed
  process
     output  "Using mymodule.xmd version " || mymodule-version-string || "%n"
     repeat to 10
        output "10fkd" % next || "%n"
     again

In this case, both functions imported from the module will be used "as is".

Importing a module in this way is best when the names exported by the module are likely unique, or when the module supplies overloadings for existing functions.

Adding a prefix to imported names

If there is a risk that the names exported by a module may also be exported by another module, or defined by the importing code, then importing names "as is" would cause a conflict. The names exported by a module can be renamed by specifying a prefix:

  import "mymodule.xmd" prefixed by my.
  process
     output  "Using mymodule.xmd version " || my.mymodule-version-string || "%n"
     repeat to 10
        output "10fkd" % my.next || "%n"
     again

In this case, all names exported by "mymodule.xmd" must be referenced in the importer as if their names began with "my.". For example, my.next refers to the function next exported by the module.

Prefixing imported names is primarily useful when the programmer wishes to make it obvious which module supplied the name being referenced, or when the names are not overloaded functions and are not likely to be unique.

Selective renaming

The names imported by a module can be renamed on a case-by-case basis:

  import "mymodule.xmd" unprefixed
     use next as random
  process
     output  "Using mymodule.xmd version " || mymodule-version-string || "%n"
     repeat to 10
        output "10fkd" % random || "%n"
     again

In this case, a call to random in the importing code will reference the exported function next from "mymodule.xmd". All other names exported from "mymodule.xmd" (like mymodule-version-string) can be referenced "as is".

If no "as" part is specified, then the name is used "as is":

  import "mymodule.xmd" prefixed by my.
     use mymodule-version-string
  process
     output  "Using mymodule.xmd version " || mymodule-version-string || "%n"
     repeat to 10
        output "10fkd" % my.next || "%n"
     again

In this case, all names exported from "mymodule.xmd" are used with a prefix of "my." except for the function mymodule-version-string which is used as is.

There's one rule that you need to be familiar with when you're using use. When you're importing a module, you only get one name for each thing imported. So if you say use for something imported, it won't be assigned another name, even if it says prefixed by at the top of the import.

Selective importing

Sometimes you don't want everything a module exports. If you want to fully control what's imported from a module—for example, when you just want one or two things from a general utility-supplying module -- you can specify only in place of unprefixed or prefixed by. only means "only import what I've listed below by use". For example:

  import "mymodule.xmd" only
     use next
  process
     repeat to 10
        output "10fkd" % next || "%n"
     again

In this case, the importer cannot call the function mymodule-version-string because the word only was used, and mymodule-version-string has not been explicitly named. As with prefixed and unprefixed imports, the imported names which are used can be renamed:

  import "mymodule.xmd" only
     use next as random
  process
     repeat to 10
        output "10fkd" % random || "%n"
     again

Re-exporting names

When a module imports another module, it may re-export names from the imported module.

The following code, when placed inside a module, re-exports all of the names from "mymodule.xmd", and exports its own function called random:

  module
  
  import "mymodule.xmd" export unprefixed
  
  export function random
    from value integer lo
    to   value integer hi
  as
    return next modulo (hi - lo) + lo

If this module were called "numbers.xmd", then importing "numbers.xmd" imports the functions random, next, and mymodule-version-string:

  import "numbers.xmd" prefixed by numbers.
  process
    output "Importing " || numbers.mymodule-version-string || "%n"
    output "Rolling the dice: "
        || "d" % numbers.random from 1 to 6 || "%n"
    output "The next number is: "
        || "d" % numbers.next || "%n"

If the re-exported names are imported with a prefix, then they are also exported with the prefix.

  module
  
  import "mymodule.xmd" export prefixed by my.
  
  export function random
    from value integer lo
    to   value integer hi
  as
    return my.next modulo (hi - lo) + lo

If this module were called "numbers.xmd", then importing "numbers.xmd" imports the functions random, my.next, and my.mymodule-version-string. Note the double-prefixing on the re-exported names:

  import "numbers.xmd" prefixed by numbers.
  process
    output "Importing " || numbers.my.mymodule-version-string || "%n"
    output "Rolling the dice: "
        || "d" % numbers.random from 1 to 6 || "%n"
    output "The next number is: "
        || "d" % numbers.my.next || "%n"

Re-exporting renamings

When an importrenames things, the renamings have to be individually exported or not:

  module
  
  import "mymodule.xmd" export prefixed by my.
    export use mymodule-version-string
  
  export function random
    from value integer lo
    to   value integer hi
  as
    return my.next modulo (hi - lo) + lo

This module exports random, mymodule-version-string, and my.next.

Re-exporting names selectively

Modules can control exactly what gets re-exported:

  module
  
  import "mymodule.xmd" prefixed by my.
    export use mymodule-version-string
  
  export function random
    from value integer lo
    to   value integer hi
  as
    return my.next modulo (hi - lo) + lo

This module re-exports mymodule-version-string, but not my.next.

Alternatively,

  module
  
  import "mymodule.xmd" export prefixed by my.
    use mymodule-version-string
  
  export function random
    from value integer lo
    to   value integer hi
  as
    return my.next modulo (hi - lo) + lo

This module re-exports my.next, but not mymodule-version-string.