Константи vs символи

  1. Надявам се кореспонденцията ми със Стефан относно константите и символите да е полезна, особено на хората, които са решили да пишат игри и са се замисляли върху това. :smiley:

    Запитване

    Пиша игра и имам клас, който представлява обект, който се движи постоянно в една посока. Тази посока се задава като аргумент(direction) на конструктора. Посоката може да е или left, или right. По-принцип, ако пиша на друг език със сигурност бих имал константи, било то в enum или не, DIRECTION.LEFT, DIRECTION.RIGHT, които да използвам, за да задам посоката. Но в Ruby има символи и мога да подходя по няколко начина.

      class MovingObject
        def initialize(direction)
          ...
        end
      end
    

    Тук direction ще се очаква да е символ :left или :right, като това ще е описано в документацията. Това, което малко ме притеснява тук е, че :left и :right малко ми приличат на тези "магически" числа/стрингове в игрите, които заместваме с константи. От една страна не се разбира какво точно :left и какво точно :right, но от друга direction подсказва, че е посока, а и в документацията ще е описано.

      class MovingObject
        module Directions
          LEFT = :left  # може и -1 например
          RIGHT = :right  # тук +1
        end
    
        def initialize(direction)
          ...
        end
      end
    

    Тук създаването на обект ще става така: MovingObject.new(MovingObject::Directions::LEFT). Малко дълго, но все още се вижда ползата от експресивността. Може вместо модул да имаме константа, която съдържа хеш и тогава указване на посока да става MovingObject::DIRECTIONS[:left].

    Общо взето се чудя дали да е символ или някаква константа, като се замислям върху варианта със символа само заради приликите със стринг, а ако използвам стринг със сигурност бих го сложил в константа.

    Предполагам, че по-идиоматично е да се използва символ, но все пак да попитам. :smile:

    Отговор

    Този Java подход е ужасен. Подавай символ. Следва кратка аргументация.

    Първо, следния абзац:

    Това, което малко ме притеснява тук е, че :left и :right малко ми приличат на тези "магически" числа/стрингове в игрите, които заместваме с константи.

    Кои магически числа и константи? 3 е магическо число, което заместваме с константата INITIAL_NUMBER_OF_LIVES. Печелим (1) четимост и (2) възможност за промяна.

    Какво печелим като заместим :left с MovingObject::Directions::LEFT? Нищо. :left е също толкова четимо колкото и LEFT, само дето няма нужда от квалификация с пълен път. Няма и за какво да го променяме. Лявото винаги ще си остане ляво (контрастирай с промяната "Началния брой животи трябва да се промени на 5").

    Ако държиш да спазваш правила сляпо, то в този случай :left не е "магическа" константа, за разлика от 3.

    Впрочем, нещо, което би спечелил, е че MovingObject::Direction::LEFT би могло да бъде ламбда вместо символ (масив с делта на координати – [1, 0]), докато :left винаги е символ. Но дори този проблем може да се реши (и то по-добре) като mapping-а между :left и ламдбата (масив с делти) става в MovingObject (или там където).

    От гледна точка на клиента на този клас, подаването на :left е напълно разумен и адекватен интерфейс.

Трябва да сте влезли в системата, за да може да отговаряте на теми.