Search code examples
smlsmlnj

SML/NJ fail to override a function in other modules


I want to override print to let it output to outstreams other than stdout. I have two files: m1.sml and main.sml in the same directory. I want to override the behavior of print in both files but it fails to override the print inside m1.sml.

m1.sml

structure Demo : sig
  val printSomething : string -> unit
  end = 
  struct
    fun printSomething s = print s
  end

main.sml

use "m1.sml";

fun redirectPrint strm str = TextIO.output (strm, str);

fun testing output = 
  let 
      val outStrm = TextIO.openOut output
      val print = redirectPrint outStrm 
  in
    (print "This will show up in test.txt\n"; 
     Demo.printSomething "This won't show up in test.txt\n"; 
     TextIO.closeOut outStrm)
  end;

testing "test.txt"

Running sml main.sml will yield

...
[autoloading done]
val redirectPrint = fn : TextIO.outstream -> TextIO.vector -> unit
val testing = fn : string -> unit
this won't show up in test.txt
val it = () : unit

As you have seen in the output, it works for the line

print "This will show up in test.txt\n" (written to test.txt)

but not the next line

Demo.printSomething "This won't show up in test.txt\n"; (printed to stdout)

which just prints to stdout.

Demo.printSomething, however, also calls print. Also, in the current scope where Demo.printSomething is called, print was overridden.

I wonder why this happens?


Solution

  • Because identifiers in ML are lexically scoped, as in all modern programming languages.