動態語言

動態程式語言是高階程式語言的一個類別，在計算機科學領域已被廣泛應用。它是一類在執行時可以改變其結構的語言：例如新的函式、物件、甚至程式碼可以被引進，已有的函式可以被刪除或是其他結構上的變化。動態語言目前非常具有活力。眾所周知的 ECMAScript（JavaScript）便是一個動態語言，除此之外如 PHP、Ruby、Python 等也都屬於動態語言，而 C、C++、Java 等語言則不屬於動態語言。

大部分動態語言都使用動態型別，但也有些不是。

特徵

動態語言可能包含的特徵有：eval 函式、物件執行時間改變、型別推論、可變記憶體分配、反射和宏。

1.1 Eval

一些動態語言提供 eval 函式。這個函式接受包含這個語言寫的程式碼的一個字串或抽象語法樹並執行它。如果這個程式碼表示了一個表示式，則返回它的結果值。和 Peter Drayton 將 eval 提供的執行時程式碼生成，同共享庫提供的動態裝載區別開來，並提醒注意在很多情況下 eval 只是用來實現高階函式（透過將函式作為字串來傳遞）或解序列化。

1.2 物件執行時間改變

在動態語言中型別或物件系統典型的是可以改變的。這意味著可以從執行時間定義或基於現存型別或物件的 mixin 來生成新物件。這還可以用來稱謂變更繼承或型別樹，從而改變了現存型別系統表現的方式（特別是關於方法呼叫）。

1.3 型別推論

由於很多動態語言具有動態型別系統，基於值的內部解釋的執行時間型別推論是一種常見任務。因為值型別在各處解釋中可以變更，它經常在進行原子性運算時使用。

1.4 可變記憶體分配

靜態程式語言（可能間接的）要求開發者在編譯之前定義使用記憶體的大小（除非採用指標機制來解決問題）。一致於物件執行時間改變，動態語言隱含的需要基於程式個別運算而（重新）分配記憶體。

1.5 反射

反射常見於很多動態語言中，典型的涉及到分析出泛型或多型資料的型別和元資料。此外它還可以包括將程式程式碼作為資料的完全求值和修改，比如 Lisp 提供的分析 S - 表示式的那種特徵。

1.6 宏

有限數目的動態語言提供一種叫做宏的特徵，用來組合程式碼內省（檢查類、函式和關鍵字來知道它們是什麼、幹什麼、知道什麼的能力）和 eval。多數當代程式設計師是從 C 或 C++ 中知道這個術語的，在這裡它們是建造入語言的小子集中的一種靜態特徵，只有在程式的文字上進行字串替換的能力。在動態語言中，它們提供對編譯器的內部工作的訪問，和對直譯器、虛擬機器或執行時系統的完全訪問，允許定義可以最佳化程式碼或修改語言的語法或文法的類似語言的構造。

例子程式碼

下列程式碼使用 Common Lisp 和它的 Common Lisp 物件系統（CLOS）展示語言的動態特徵，具體採用的實現是 SBCL。

2.1 程式碼在執行時間算得和後期繫結

這個例子展示函式可以在執行時間從原始碼進行修改：

 原始碼作為資料儲存在一個變數中

(defparameter best-guess-formula '(lambda (x) (* x x 2.5)))
BEST-GUESS-FORMULA

 從原始碼建立一個函式並在執行時間執行，這個函式可獲得於 best-guess 名下

(compile 'best-guess best-guess-formula)

BEST-GUESS

NIL

NIL

 這個函式可以被呼叫

(best-guess 10.3)

265.225

 原始碼可以在執行時間改進

(setf best-guess-formula `(lambda (x) ,(list'sqrt (third best-guess-formula))))

(LAMBDA (X) (SQRT (* X X 2.5)))

 這個函式的新版本被編譯

(compile 'best-guess best-guess-formula)

BEST-GUESS

NIL

NIL

 下次呼叫將呼叫新版本，這是後期繫結的特徵

(best-guess 10.3)

16.28573

2.2 物件執行時間改變

這個例子展示，現存的例項在它的類變更時可以被變更來包括一個新槽，還有現存的方法可以被替代為新版本：

 person 類，person 有一個 name

(defclass person ((name :initarg :name)))

 給類 person 的物件的一個定製的列印方法

(defmethod print-object ((p person) stream)

(print-unreadable-object (p stream :type t)

(format stream "~a" (slot-value p 'name))))

 一個例子 person 例項

(defparameter person-1 (make-instance 'person :name "Eva Luator"))

 類 person 得到第二個槽，它從而擁有槽 name 和 age

(defclass person ((name :initarg :name) (age :initarg :age :initform :unknown)))

 更新列印這個物件的方法

(defmethod print-object ((p person) stream)

(print-unreadable-object (p stream :type t)

(format stream "~a age: ~d" (slot-value p 'name) (slot-value p 'age))))

WARNING:

redefining PRINT-OBJECT (#

) in DEFMETHOD

 現存的物件已經被變更了，它有了增加的槽和新的 print 方法

*person-1#

 可以設定例項的新 age 槽

(setf (slot-value person-1 'age) 25)

25

 這個物件已經被更新

*person-1#

2.3 基於例項的類的程式碼在執行時間組裝

在下列例子中，類 person 得到一個新超類。print 方法得到重新定義，它組裝了多個方法成為有效（effective）方法。基於實際引數的類和執行時間可獲得和適用的方法，有效方法得以組裝：

 類 person

(defclass person ((name :initarg :name)))

 person 只打印它的 name

(defmethod print-object ((p person) stream)

(print-unreadable-object (p stream :type t)

(format stream "~a" (slot-value p 'name))))

 一個 person 例項

(defparameter person-1 (make-instance 'person :name "Eva Luator"))
PERSON-1

 顯示這個 person 例項

*person-1#

 現在重新定義 print 方法為可擴充套件的

 :around 方法建立 print 方法的上下文，並且它呼叫 call-next-method

(defmethod print-object :around ((p person) stream)

(print-unreadable-object (p stream :type t)

(call-next-method)))

 主要方法列印 name

(defmethod print-object ((p person) stream)

(format stream "~a" (slot-value p 'name)))

WARNING:

redefining PRINT-OBJECT (#

) in DEFMETHOD

 新類 id-mixin 提供了一個 id

(defclass id-mixin ((id :initarg :id)))

 :after 方法只打印 id 槽的值

(defmethod print-object :after ((object id-mixin) stream)

(format stream "ID: ~a" (slot-value object 'id)))

 現在重新定義類 person 來包括混入的 id-mixin

(defclass person (id-mixin) ((name :initarg :name)))

 現存例項 person-1 現在有了一個新槽並設定它為 42

(setf (slot-value person-1 'id) 42)

42

 再次顯示這個物件，print-object 函式現在有一個有效方法，它呼叫三個方法：:around 方法、主要方法和:after 方法

*person-1#

語言

APL
C#（≥4.0）
ChucK
Clipper
Curl
D
ECMAScript
ActionScript
JavaScript
Eiffel
Erlang
Forth
Groovy
HyperCard/
Io
Lisp
Scheme
Common Lisp
Clojure
Dylan
Emacs Lisp
newLISP
PicoLisp
Logo
Lua
Oberon
Objective-C
Perl
PHP
Pike
Prolog
Python
R
REALbasic
REBOL
Ruby
Scala
Scratch
Smalltalk
Self
Squeak
Pharo
SNOBOL
SuperCollider
Tcl
TeX
VBScript
Visual Basic 9+
Visual FoxPro
PowerShell