Class-only programming

image



In my post Implementing numbers in "pure" Ruby ( "Develop a number on a" pure "Ruby"), I outlined a framework that permits the use of basic things like Ruby's equality operator, true/ false, nil, blocks, etc.



But what if we had nothing at all? Even basic operators like ifand while? Get ready for a dose of pure object-oriented madness.



Framework



  • We can define classes and methods
  • , Ruby . , . nil
  • , — (x = something).


if-? ? !



— . ? :



, Ruby - "Boolean". , (nil false Ruby;

false, 0 '' JS). , . .





, :



class BaseObject
  def if_branching(then_val, _else_val)
    then_val
  end
end


if_branching — . , , , then_val.



? null:



class NullObject < BaseObject
  def if_branching(_then_val, else_val)
    else_val
  end
end


, .



Ruby Object. BasicObject, . Object:



class NormalObject < BaseObject
end


, NormalObject. ( #null?).



If-



, if-:



class If < NormalObject
  def initialize(bool, then_val, else_val = NullObject.new)
    @result = bool.if_branching(then_val, else_val)
  end

  def result
    @result
  end
end


! . .



:



class Fries < NormalObject
end

class Ketchup < NormalObject
end

class BurgerMeal < NormalObject
  def initialize(fries = NullObject.new)
    @fries = fries
  end

  def sauce
    If.new(@fries, Ketchup.new).result
  end
end

BurgerMeal.new.sauce # ==> NullObject
BurgerMeal.new(Fries.new).sauce # ==> Ketchup


, : " , ?". ""?



:



# 
if today_is_friday?
  order_beers()
else
  order_tea()
end

#  If 
If.new(today_is_friday?, order_beers(), order_tea()).result


. - , .



() , .. .



. (. "callable"):



class OrderBeers
  def call
    # do something
  end
end

class OrderTea
  def call
    # do something else
  end
end

If.new(today_is_friday?, OrderBeers.new, OrderTea.new)
  .result
  .call


, , #call. . If.



( , )



(null ), . :



class Bool < NormalObject; end

class TrueObject < Bool; end

class FalseObject < Bool
  def if_branching(_then_val, else_val)
    else_val
  end
end


Bool, TrueObject ( , .. )

FalseObject, #if_branching , NullObject.



. . :



class BoolNot < Bool
  def initialize(x)
    @x = x
  end

  def if_branching(then_val, else_val)
    @x.if_branching(else_val, then_val)
  end
end


- "" #if_branching. , .





, — . . While.



:



while some_condition
  do_something
end


: " , ".



, — . !



class While < NormalObject
  def initialize(callable_condition, callable_body)
    @cond = callable_condition
    @body = callable_body
  end

  def run
    is_condition_satisfied = @cond.call
    If.new(is_condition_satisfied,
           NextIteration.new(self, @body),
           DoNothing.new)
      .result
      .call
  end

  #  ""    While#run.
  #     
  # (,     )
  class NextIteration < NormalObject
    def initialize(while_obj, body)
      @while_obj = while_obj
      @body = body
    end

    def call
      @body.call
      @while_obj.run
    end
  end

  class DoNothing < NormalObject
    def call
      NullObject.new
    end
  end
end




, null-.





:



class List < NormalObject
  def initialize(head, tail = NullObject.new)
    @head = head
    @tail = tail
  end

  def head
    @head
  end

  def tail
    @tail
  end
end


- ( #each !). , :



#
#     
#
class ListWalk < NormalObject
  def initialize(list)
    @left = list
  end

  def left
    @left
  end

  #        current.
  #  null   
  def next
    head = If.new(left, HeadCallable.new(left), ReturnNull.new)
             .result
             .call
    @left = If.new(left, TailCallable.new(left), ReturnNull.new)
              .result
              .call
    head
  end

  def finished?
    BoolNot.new(left)
  end

  class HeadCallable < NormalObject
    def initialize(list)
      @list = list
    end

    def call
      @list.head
    end
  end

  class TailCallable < NormalObject
    def initialize(list)
      @list = list
    end

    def call
      @list.tail
    end
  end

  class ReturnNull < NormalObject
    def call
      NullObject.new
    end
  end
end


, . #head #tail, null-pointer ( , null null, ).





, :



class Counter < NormalObject
  def initialize
    @list = NullObject.new
  end

  def inc
    @list = List.new(NullObject.new, @list)
  end

  class IncCallable < NormalObject
    def initialize(counter)
      @counter = counter
    end

    def call
      @counter.inc
    end
  end

  def inc_callable
    IncCallable.new(self)
  end
end


. ( ).



#inc_callable. , "" , , _callable . - .



null



null. NormalObject NullObject #null? ( #nil? Ruby):



class NormalObject < BaseObject
  def null?
    FalseObject.new
  end
end

class NullObject < BaseObject
  def null?
    TrueObject.new
  end
end


null-:



#
#  ,     NullObject  
#
class CountNullsInList < NormalObject
  def initialize(list)
    @list = list
  end

  def call
    list_walk = ListWalk.new(@list)
    counter = Counter.new

    While.new(ListWalkNotFinished.new(list_walk),
              LoopBody.new(list_walk, counter))
         .run

    counter
  end

  class ListWalkNotFinished < NormalObject
    def initialize(list_walk)
      @list_walk = list_walk
    end

    def call
      BoolNot.new(@list_walk.finished?)
    end
  end

  class LoopBody < NormalObject
    class ReturnNull < NormalObject
      def call
        NullObject.new
      end
    end

    def initialize(list_walk, counter)
      @list_walk = list_walk
      @counter = counter
    end

    def call
      x = @list_walk.next
      If.new(x.null?, @counter.inc_callable, ReturnNull.new)
        .result
        .call
    end
  end
end


. null- .





- — , , . , , (!), - . , : . — (, null, NullObject). , ...



experiments.




All Articles