Pull to refresh
0
0
Send message

Есть ещё очень крутой GSAP ScrollTrigger

И какие гарантии дает GDScript? Он такой же динамический как и Lua. По ссылке сказано что его придумали только потому что задолбались писать байндинги внутренностей движка к языку общего назначения.

Зачем в начале упоминается GDScript? Он с питоном не связан никак кроме похожего синтаксиса и не является языком общего назначения.

Да, конечно будет кучу памяти отжирать. Но гигабайт данных отправлять в браузер одним куском, без пагинации? Тут у JS начнутся проблемы, не только у редакса. Это особенный случай, и решение понадобится тоже особое.

http://openworm.org/ — симулируют круглого червя Caenorhabditis elegans.

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::ATTACK (2)>
when called with arguments
  (#<WIZARD {1005F6AB23}> #<WIZARD {10060999F3}>).
   [Condition of type SB-PCL::NO-APPLICABLE-METHOD-ERROR]

Чтобы это исправить надо либо добавить конкретную реализацию для это случая


(defmethod attack ((attacker wizard) (target wizard)))

либо сделать какой-нибудь общий метод, который будет ловить все комбинации


(defmethod attack ((attacker creature) (target creature)))

Ну возможно, но в любом случае инкапсуляция старее ооп.

А подпрограммы, которые задают поведение объектов называют методами. Как правило, набор методов свой у каждого класса, а не у каждого объекта. Чтобы каждый объект определённого класса вёл себя как и другие объекты того же класса. Буду рад узнать из комментариев о языках, где дело обстоит иначе

Дело обстоит немного иначе в языках реализующих metaobject protocol (Common Lisp Object System), да и вообще в языках в которых есть мультиметоды или multiple dispatch (Common Lisp, Clojure, Julia, C#). Там методы не принадлежат классам — классы это просто тип структуры. А методы реализуются над классами, и один и тот-же метод может быть объявлен для нескольких классов.


(defclass entity ()
  ((x :initarg :x :initform 0)
   (y :initarg :y :initform 0))
  (:documentation "Базовый класс сущности на карте"))

(defclass creature (entity)
  ((hp :initarg :hp :initform 100)
   (mana :initarg :mana :initform 0))
  (:documentation "Живое существо, наследник класса entity"))

Придумываем два типа существ. Обратите внимание — никаких методов внутри класса.


(defclass warrior (creature) ()
  (:default-initargs :hp 200 :mana 0)
  (:documentation "Воин"))

(defclass wizard (creature) ()
  (:default-initargs :hp 50 :mana 100)
  (:documentation "Волшебник"))

(setf conan (make-instance 'warrior))
(setf merlin (make-instance 'wizard))

(describe conan)
;#<WARRIOR {10033335F3}>
;  [standard-object]
;  X                              = 0
;  Y                              = 0
;  HP                             = 200
;  MANA                           = 0

(describe merlin)
;#<WIZARD {1002F1C9F3}>
;  [standard-object]
;  X                              = 0
;  Y                              = 0
;  HP                             = 50
;  MANA                           = 100

Научим их перемещаться.


(defgeneric walk (entity x y)
  (:documentation "Перемещает сущность на новое место"))

(defmethod walk (creature d-x d-y)
  (with-slots (x y) creature
    (setf x d-x)
    (setf y d-y)))

(walk conan 10 50)
(walk merlin 5 20)

(describe conan)
;#<WARRIOR {10033335F3}>
;  [standard-object]
;  X                              = 10
;  Y                              = 50
;  HP                             = 200
;  MANA                           = 0

(describe merlin)
;#<WIZARD {1002F1C9F3}>
;  [standard-object]
;  X                              = 5
;  Y                              = 20
;  HP                             = 50
;  MANA                           = 100

Пока все очень похоже на обычные ООП-языки. Зачем выносить метод из класса пока не очень понятно. Приведем пример еще одного метода.


(defgeneric attack (attacker target)
  (:documentation "Позволяет одному существу атаковать другое"))

(defmethod attack ((attacker warrior) (target wizard))
  (with-slots (hp) target
    (decf hp 20)))

(defmethod attack ((attacker wizard) (target warrior))
  (with-slots (mana) attacker
    (decf mana 10))
  (with-slots (hp) target
    (decf hp 40)))

(attack conan merlin)
(attack merlin conan)

(describe conan)
;#<WARRIOR {10033335F3}>
;  [standard-object]
;  X                              = 10
;  Y                              = 50
;  HP                             = 160
;  MANA                           = 0

(describe merlin)
;#<WIZARD {1002F1C9F3}>
;  [standard-object]
;  X                              = 5
;  Y                              = 20
;  HP                             = 30
;  MANA                           = 90

Метод attack диспатчится используя классы аргументов attacker и target. Когда воин атакует волшебника вызывается одна реализация метода, когда волшебник атакует воина — другая. Получается что метод attack нельзя положить ни внутрь класса warrior, ни внутрь класса wizard — он принадлежит одновременно обеим классам.


Такой вот гибкий полиморфизм.

Еще один пример того что инкаспуляция не имеет отношения к ООП — ее тривиально можно организовать в функциональном стиле при помощи замыканий. Например есть счетчик, который можно только инкрементировать и обнулять. Отрицательное значение для счетчика — это ошибка.


let createCounter = () => {
    var count = 0;
    return [
        () => {count = 0; return count},
        () => {count += 1; return count}
    ]
}

let [reset, inc] = createCounter();
inc()    // 1
inc()    // 2
inc()    // 3
reset()  // 0
inc()    // 1

Здесь без хитростей уже не залезть внутрь замыкания. Прямого доступа к переменной нет, нужно пользоваться интерфейсом из двух функций который вернул createCounter.

Information

Rating
Does not participate
Registered
Activity