函數別名與載入設定(Overloading and Autoloading)

dispatch() 函數可以建立函數的別名(alias),它可以將一個函數所有的呼叫都重新導向至另一個函數,或是只針對一些特定的變數類型,例如:

function y = spsin (x)
  printf ("Calling spsin\n");
  fflush(stdout);
  y = spfun ("sin", x);
endfunction

spsin() 是一個自行定義的函數,接著建立函數別名:

dispatch ("sin", "spsin", "sparse matrix");

這樣會將會將函數 spsin() 建立一個別名為 sin(),但此別名只有針對 sparse matrix 的變數類型,

y0 = sin(eye(3))

因為 eye(3) 不是 sparse matrix,所以會使用原本內建的 sin() 函數,輸出為

y0 =

   0.84147   0.00000   0.00000
   0.00000   0.84147   0.00000
   0.00000   0.00000   0.84147
y1 = sin(speye(3))

這裡的 speye(3) 是一個 sparse matrix,所以會呼叫 spsin() 函數,輸出為

Calling spsin
y1 =

Compressed Column Sparse (rows = 3, cols = 3, nnz = 3 [33%])

  (1, 1) ->  0.84147
  (2, 2) ->  0.84147
  (3, 3) ->  0.84147

內建的 sin() 函數其實本來就可以處理 sparse matrix,這裡只是為了示範別名的用法才如此使用。

dispatch (f, r, type)

dispatch(f, r, type) 函數會建立一個 r() 函數的別名,使 f() 函數在傳入的第一個參數為 type 類型時,以 r() 函數取代。若將 type 設為 "any",則當沒有其他的類型的別名時,都會呼叫 r()。建立別名之後,原始的 f() 函數可以使用 builtin(f, ...) 函數來呼叫。

若呼叫 dispatch() 函數而省略 r 參數,則會將作用於 f() 函數 type 類型的別名移除;若省略 rtype 兩個參數,則會顯示 f() 函數所有的別名。

[...] builtin (f, ...)

builtin(f, ...) 函數會忽略別名呼叫原始的 f() 函數。

透過別名可以將一個函數連結至許多個函數,若是使用者在命令列中輸入一個函數的別名,而此別名所指向的函數事實上是儲存在另外一的檔案中,此時 Octave 若以函數的名稱去搜尋檔案,就會發生找不到函數檔案的問題,最簡單的解決方法就是將此函數的定義檔複製一份,並以別名的名稱命名,但是這樣又會浪費硬碟空間。比較好的做法是使用 autoload() 函數設定函數的儲存位置。

autoload (function, file)

autoload(function, file) 函數會設定函數 function 的儲存位置為 file 檔案,當 Octave 要載入 function 函數時,就會從 file 檔案中載入。

file 參數應為一個絕對路徑,若設為不含路徑的檔名,則此檔案必須與 autoload() 函數所在的檔案有相同的路徑,此檔案不可依靠載入路徑來載入。

一般來說在 autoload() 函數會用在 ADD_PKG 這個特殊的指令稿中,在載入路徑的目錄中若包含此指令稿,則在此路徑加入目前的載入路徑時,就會自動執行 ADD_PKG,這個指令稿中可以設定這個目錄中函數的載入方式:

autoload ("foo", "bar.oct");

這會設定 foo() 函數所載入的檔案為 bar.oct

若呼叫 autoload() 函數沒有加任何參數,則會顯示目前所有函數的載入設定表。

函數鎖定(Function Locking)

mlock() 可以將函數鎖定在記憶體中,不要被 clear() 函數移除,這個常會用在 oct 檔或 mex 檔中包含初始化的函數,讓 clear() 函數不要刪除已經初始化的內容。例如:

function count_calls ()
  mlock ();
  persistent calls = 0;
  printf ("'count_calls' has been called %d times\n", ++calls);
endfunction

這樣會鎖定 count_calls() 函數,使其不會被 clear() 函數刪除:

count_calls ();

輸出為

'count_calls' has been called 1 times
clear count_calls;
count_calls ();

輸出為

'count_calls' has been called 2 times

要查詢函數是否有被鎖定,可用 mislocked() 函數:

mislocked ("count_calls")

而要解除鎖定可以使用 munlock() 函數:

munlock ("count_calls");
mlock ()

mlock() 函數會將目前的函數鎖定,讓此函數不會被 clear() 函數刪除。

munlock (fcn)

munlock(fcn) 函數會將 fcn 函數解除鎖定,若不指定 fcn 參數,則會將目前的函數解除鎖定。

mislocked (fcn)

mislocked(fcn) 函數可以判斷 fcn 函數是否被鎖定,若不指定 fcn 參數,則會判斷目前的函數是否被鎖定。

函數優先權(Function Precedence)

在 Octave 中有許多種定義函數的方式,當同一個函數名稱有多種定義方式時,就會依照函數優先權(Function Precedence)來決定使用哪一個,以下是 Octave 的所使用的優先權列表:

  1. 子函數(subfunction):目前函數的子函數,請參考子函數。
  2. 私有函數(private function):目前函數的私有函數,請參考私有函數。
  3. Class constructor:建構使用者類別的函數。
  4. Class method:類別的多載函數。
  5. 函數別名:請參考函數別名與載入設定。
  6. 命令列函數(Command-line Function):由命令列中所定義的函數。
  7. 自訂載入函數(Autoload function):經由 autoload() 所設定的函數,請參考函數別名與載入設定。
  8. 載入路徑中的函數:包含載入路徑中各類型的檔案,載入的優先順序為 .oct 檔、 .mex 檔、 .m 檔。
  9. 內建函數(Built-in function):Octave 中本身內建的函數,例如:numel()size() 等。