Skip to content

Instantly share code, notes, and snippets.

@akuklev
Created June 20, 2023 17:00
Show Gist options
  • Save akuklev/393a2bd89869946f556286e8c1ae71a5 to your computer and use it in GitHub Desktop.
Save akuklev/393a2bd89869946f556286e8c1ae71a5 to your computer and use it in GitHub Desktop.
Поля и методы

В большинстве объектно-ориентированных языков программирования точка используется и для полей (user.name) и для методов (stream.write(s)), что приводит к двусмысленности, поскольку в поле m.sinвообще-то может храниться функция, и её вообще-то может хотеться применить к какому-то аргументу m.sin(x), что выглядит точно как вызов метода, но устроено совершенно по-другому: метод получает в распоряжение объект, относительно которого вызывается, функция вообще говоря нет.

Синтаксически я считаю идеальным использовать для методов треугольничек вправо вместо точки.

То есть point.x, или s.length, или list.size, но file ▸close и

files ▸filter { it.size > 0 } ▸map { it.name }

И особенно

n ▸elim {
  is Zero1
  is Positive ↦ it · this(it.prev)
}

Мне вообще нравится использовать ▸ как оператор обратного применения, то есть x ▸ f := f(x), и это очень хорошо сочетается с применением ▸ без пробела справа в качестве замены точки при вызове методов.

Дело в том, что если мы имеем дело с данными (такими как натуральное число n или список files), то “методы” это на самом деле поля из объекта-компаньона, применённые сперва к аргументам справа, а потом к значению слева. То есть,

n ▸elim(motive)
// := n ▸ Nat.elim(motive)

files ▸filter { it.size > 0 } ▸map { it.name }
// := files ▸ List.filter { it.size > 0 } ▸ List.map { it.name }.

Отмечу, что в языке с тайпклассами переменный тип T может иметь объект-компаньон:

fun<T : Serializable> foo(t : T) {
   ...
   t ▸serialize
   // := t ▸ T.serialize
}


fun<C<T> : Functorial> foo(t : C<Int>) {
   ...
   t ▸map {it + 1}
   // := t ▸ C.map {it + 1}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment