• О проблемах транслятора Python и переосмысление языка
    +1

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

  • О проблемах транслятора Python и переосмысление языка
    0

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

  • Redux Toolkit как средство эффективной Redux-разработки
    0

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

  • Hello World из байт-кода для JVM
    +1

    Вдогонку — Hexing the technical interview

  • Космики. 7 лет
    +1

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

  • ООП, «святая троица» и SOLID: некоторый минимум знаний о них
    0
    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)))
  • ООП, «святая троица» и SOLID: некоторый минимум знаний о них
    0

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

  • ООП, «святая троица» и SOLID: некоторый минимум знаний о них
    +3
    А подпрограммы, которые задают поведение объектов называют методами. Как правило, набор методов свой у каждого класса, а не у каждого объекта. Чтобы каждый объект определённого класса вёл себя как и другие объекты того же класса. Буду рад узнать из комментариев о языках, где дело обстоит иначе

    Дело обстоит немного иначе в языках реализующих 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 — он принадлежит одновременно обеим классам.


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

  • ООП, «святая троица» и SOLID: некоторый минимум знаний о них
    –1

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


    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.