Динамички програмски језик

Из Википедије, слободне енциклопедије

Динамички програмски језик је термин који се користи у рачунарској науци да опише класу програмских језика на високом нивоу које, компоненте, извршавају многа заједничка програмска понашања која статички програмски језици врше током компилације. Ова понашања могу укључивати продужење програма, додајући нову шифру, проширујући објекте и дефиниције, или модификација типа система. Иако слична понашања могу емулирати у готово било ком језику, уз различите степене тежине, сложености и перформанси трошкова, динамички језици дају директне алате да искористе од њих. Многе од ових функција су прво имплементиране као матерње функције у Lisp програмском језику.

Најдинамичнија језици су такође динамички откуцани, али нису сви. Динамички језици се често (али не увек) називају "скрипт језици", иако се термин "скрипт језик" у најужем смислу односи на језике који су специфични за дато компонентно окружењу.

Имплементација[уреди]

Евал[уреди]

Неки динамички језици нуде евал функцију. Ова функција узима параметар стринг који садржи код у језику, и извршава га. Ако је овај код скраћеница за израз, добијена вредност се враћа. Међутим, Ерик Меијер и Петер Драитон указују на то да програмери "користе евал као сиромашну човек замену за функције вишег реда."[1]

Објекат компонентна промена[уреди]

Врста објекта или система може обично да се мења у току извршавања у динамичном језику. То може да значи стварање нових објеката из дефиниције компоненте или на основу mixins постојећих врста или објеката. То такође може да се односи на промену наследства или типа дрва, и на тај начин мењајући начин на који се постојећи типове понашају (посебно у односу на позивање метода).

Функционално програмирање[уреди]

Функционални програмски концепти су карактеристика многих динамичких језика, а такође произилазе из Lisp.

Затварање[уреди]

Један од најчешће коришћених аспеката функционалног програмирања у динамичким језицима је затварање, који омогућава креирање нове инстанце функције које задржава приступ контекста у коме је настала. Једноставан пример за то је стварање функција за скенирање текста за речи:

function нови скенер (реч)
  temp_function = function (улазни)
    скенирање за текст (улазно, реч)
  end function
  return temp_function
end function

Ваља имати на уму да унутрашња функција нема име, а уместо тога чува у променљивој temp_function-и. Сваки пут new_scanner се извршава, он ће вратити нову функцију која памти вредност речи параметара који су усвојени када је дефинисан.

Затварање [2] је један од кључних инструмената функционалног програмирања, а многи језици подржавају најмање овај степен функционалног програмирања.

Наставак[уреди]

Друга карактеристика неких динамичких језика је наставак. Наставака представља извршење стања које се могу поново позвати. На пример, анализатор може да врати средњи резултат и наставак који, када се позове, ће наставити да анализира улаз. Наставак комуницира у веома сложеним начинима за одређивање оквира, посебно у погледу затварања. Из тог разлога, многи динамички језици не дају наставке.

Одраз[уреди]

Одраз је уобичајен у многим динамичким језицима, и обично укључује анализу типова и метаподатака генеричких или полиморфних података. То, међутим, такође укључује пуну процену и модификацију програмског кода податка, као што су функције које пружа Lisp, у анализи С-израза.

Макрои[уреди]

Ограничен број динамичких програмским језика пружа могућности које комбинују код интроспекције (способност да испита класе, функције и кључне речи да знају шта су, шта раде и шта знају) и евал  под називом макрои. Већина програмера данас који су свесни термина макро срели су га у  C или C++, где су статичне карактеристике које се уграђују у мали подскупу језика, и да су способне само за стринг замене на тексту програма. У динамичким језицима, међутим, они дају приступ унутрашњим пословима преводиоца и пуни приступ преводиоцу, виртуелне машине, или компоненти, која омогућава дефинисање језика налик конструкцији која може оптимизирати код или модификује синтаксу или граматику језика.

АсемблерC, C++, рана Java и ФОРТРАН се генерално не уклапају у ову категорију.

Примери[уреди]

Следећи примери показују динамичке карактеристике употребе језика Common Lisp и његов Common Lisp Object System.

Обрачунавање кода на издржљивости и касно везивање[уреди]

Пример показује како се функција може мењати у току рада из обрачунатог изворног кода

; изворни код се чува као података у променљивој
CL-USER > (defparameter *best-guess-formula* '(lambda (x) (* x x 2.5)))
*BEST-GUESS-FORMULA*

; функција је створен од кода и састављена у току рада, функција је доступан под именом најбољи-гуесс
CL-USER > (compile 'best-guess *best-guess-formula*)
#<Function 15 40600152F4>

; функција се може назвати
CL-USER > (best-guess 10.3)
265.225

; изворни код може бити побољшан у току рада
CL-USER > (setf *best-guess-formula* `(lambda (x) ,(list 'sqrt (third *best-guess-formula*))))
(LAMBDA (X) (SQRT (* X X 2.5)))

; нова верзија функције се саставља
CL-USER > (compile 'best-guess *best-guess-formula*)
#<Function 16 406000085C>

; следећи позив ће позвати нову функцију, функцију у последње време везивања
CL-USER > (best-guess 10.3)
16.28573

Објекат компонентна промена[уреди]

Овај пример показује како се постојећи пример мења укључујући нови слот кад се класа промени и да се постојећи начин може заменити са новом верзијом.

; особа класа. Особа има име.
CL-USER > (defclass person () ((name :initarg :name)))
#<STANDARD-CLASS PERSON 4020081FB3>

; обичај штампања метода за објекте класе особе
CL-USER > (defmethod print-object ((p person) stream)
            (print-unreadable-object (p stream :type t)
              (format stream "~a" (slot-value p 'name))))
#<STANDARD-METHOD PRINT-OBJECT NIL (PERSON T) 4020066E5B>

; један пример особа инстанца
CL-USER > (setf *person-1* (make-instance 'person :name "Eva Luator"))
#<PERSON Eva Luator>

; класа особа добија други слот. Она тада има назив слот и старост.
CL-USER > (defclass person () ((name :initarg :name) (age :initarg :age :initform :unknown)))
#<STANDARD-CLASS PERSON 4220333E23>

; ажурирање метода за штампање објекат
CL-USER > (defmethod print-object ((p person) stream)
            (print-unreadable-object (p stream :type t)
              (format stream "~a age: ~" (slot-value p 'name) (slot-value p 'age))))
#<STANDARD-METHOD PRINT-OBJECT NIL (PERSON T) 402022ADE3>

; постојећи објекат се сада променио, она има додатни слот и нови метод за штампање
CL-USER > *person-1*
#<PERSON Eva Luator age: UNKNOWN>

; можемо поставити ново доба слот за пример
CL-USER > (setf (slot-value *person-1* 'age) 25)
25

; објекат је ажуриран
CL-USER > *person-1*
#<PERSON Eva Luator age: 25>

Склапање кода компонентне основе на класи случајева[уреди]

У следећем примеру класа особа добија нову суперкласу. Метод за штампање је редефинисана тако да окупља неколико метода у ефективном методу. Ефективна метода је монтирана на основу класе аргумента и компонента на располагању и важећим методама.

; класа особа
CL-USER > (defclass person () ((name :initarg :name)))
#<STANDARD-CLASS PERSON 4220333E23>

; особа само исписује своје име
CL-USER > (defmethod print-object ((p person) stream)
            (print-unreadable-object (p stream :type t)
              (format stream "~a" (slot-value p 'name))))
#<STANDARD-METHOD PRINT-OBJECT NIL (PERSON T) 40200605AB>

; особа инстанца
CL-USER > (defparameter *person-1* (make-instance 'person :name "Eva Luator"))
*PERSON-1*

; приказује особу инстанцу
CL-USER > *person-1*
#<PERSON Eva Luator>

; сада редефинисање начина штампања да би био проширив
; округли метод ствара контекст за методе за штампу и позива следећи начин
CL-USER > (defmethod print-object :around ((p person) stream)
            (print-unreadable-object (p stream :type t)
              (call-next-method)))
#<STANDARD-METHOD PRINT-OBJECT (:AROUND) (PERSON T) 4020263743>

; примарни метод исписује име
CL-USER > (defmethod print-object ((p person) stream)
            (format stream "~a" (slot-value p 'name)))
#<STANDARD-METHOD PRINT-OBJECT NIL (PERSON T) 40202646BB>

; нова класа id-mixin даје id
CL-USER > (defclass id-mixin () ((id :initarg :id)))
#<STANDARD-CLASS ID-MIXIN 422034A7AB>

; метод за штампање само исписује вредност id слота
CL-USER > (defmethod print-object :after ((object id-mixin) stream)
          (format stream " ID: ~a" (slot-value object 'id)))
#<STANDARD-METHOD PRINT-OBJECT (:AFTER) (ID-MIXIN T) 4020278E33>

; сада редефинишу класе особу да се укључи у mixin id-mixin
CL-USER 241 > (defclass person (id-mixin) ((name :initarg :name)))
#<STANDARD-CLASS PERSON 4220333E23>

; постоји инстанца * Лице-1 * сада има нови слот и ми га постављамо на 42
CL-USER 242 > (setf (slot-value *person-1* 'id) 42)
42

; приказивање објеката поново. Функција штампања објеката сада има ефикасну методу, којом се позивају три методе: метод около, примарни метод и после методом.
CL-USER 243 > *person-1*
#<PERSON Eva Luator ID: 42>

Примери динамичких програмских језика[уреди]

Популарни динамички програмски језици укључују JavaScript, Python, Ruby, PHP, Lua и Perl. Следећи се генерално сматрају динамичке језике:

Види још[уреди]

Референце[уреди]

  1. Meijer, Erik and Peter Drayton (2005), Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages, Microsoft Corporation, CiteSeerX: 10.1.1.69.5966 
  2. See example of use on pp. 330 of Larry Wall's Programming Perl. ISBN 0-596-00027-8.
  3. Chapter 24. Dynamic language support. Static.springsource.org. Retrieved on 2013-07-17.
  4. <http://groovy.codehaus.org/

Литература[уреди]

Спољашње везе[уреди]

(Многи користе израз "скрипт језици".)