インスタンスが属するクラスをあとから変更する操作を Cyan で

インスタンスが属するクラスをあとから変更する操作をいろいろな言語で - Smalltalkのtは小文字です
parentをさくっと書き換えられるのでお題に書いてある条件だけならクリアできるけど、不要なスロットを消したりまるっとスロットを取っ替えたりできないので残念な感じ。
といってもrubyのremove_methodみたいなのってどういう時に必要になるのか分かってないですすみません。

Cyanには小数やsqrt, sin等の算術関数がないので、座標変換じゃなくて簡単な色空間変換(RGB <=> CMYK)のコードを書いてみた。式はISP imaging-developersから。

mac(copy_slots)^(c, o):
  `begin:
    (?o).slots().map^(s, v):
      slot := Messenger.new(?c, s)
      Messenger.new(Quote.new(slot), ('x.(=)).message, &(v)).eval()
    ?c

class(RGB)^:
  def(init)^(&opt r=0, g=0, b=0):
    $(.r, .g, .b) = &(r, g, b)

  def(to_cmyk)^(&opt scale = 100):
    k := scale-scale*(.r.max(.g, .b))/255
    $(c, m, y) := if (k == scale): &(0, 0, 0)
      else: &(*[.r, .g, .b].map^(v){ scale*(scale-scale*v/255-k)/(scale-k) })
    CMYK.new(c, m, y, k, scale)

  def(to_cmyk!)^: copy_slots(self, .to_cmyk())

  def(to_s)^: [.r, .g, .b].to_s()


class(CMYK)^:
  def(init)^(&opt c=0, m=0, y=0, k=100, scale=100):
    $(.c, .m, .y, .k, .scale) = &(c, m, y, k, scale)

  def(to_rgb)^:
    RGB.new(*[.c, .m, .y].map^(v){ 255-255*.scale.min(v*(.scale-.k)/.scale+.k)/.scale })

  def(to_rgb!)^: copy_slots(self, .to_rgb())

  def(to_s)^: [.c, .m, .y, .k].to_s() + "/" + .scale.to_s()

スロットのコピーはもっとマシな書き方がある気が…

以下確認

cyan> load "colors.cy"
 => true
cyan> col1 = col2 = CMYK.new(80, 0, 0, 0, 100)  # cyan 80%
 => #<obj 4e677480>
cyan> col1.parent == CMYK
 => true
cyan> col1.to_rgb!()
 => #<obj 4e677480>
cyan> col2.to_rgb!()
(stdin):2: error: invalid message for #<obj 4e677480>: to_rgb!
cyan> (col1.parent == RGB) && col1.to_s()
 => "[51, 255, 255]"
cyan> (col2.parent == RGB) && col2.to_s()
 => "[51, 255, 255]"
cyan> col2.r = 0
 => 0
cyan> col2.to_cmyk!()
 => #<obj 4e677480>
cyan> col1.to_cmyk!()
(stdin):2: error: invalid message for #<obj 4e677480>: to_cmyk!
cyan> (col1.parent == CMYK) && col1.to_s()
 => "[100, 0, 0, 0]/100"
cyan> (col2.parent == CMYK) && col2.to_s()
 => "[100, 0, 0, 0]/100"
cyan> col2.slots()
 => %{ parent => #<obj 70ec6700>, c => 100, m => 0, y => 0, k => 0, scale => 100, r => 0, g => 255, b => 255 }

一応補足

普通画像処理アプリでのRGB <=> CMYK変換はこんな単純な計算ではなく、間に別の色空間への展開等を挟んだりするらしい。
でもこれくらいならチュートリアルやゴルフのお題に良いかも。