Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Устаревшие типы (LambdaN, Block), # в параметре

Устаревшие LambdaN, Block, # в параметре

Исторически в Libretto есть псевдоструктуры в пакете libretto для представления т.н. “лямбд” и “блоков”: Block (синоним Lambda0), Lambda0, Lambda1, Lambda2 и т.д.

Их особенность в том, что они используют наименее специфичный тип Any* для параметров и результата (но с возможным скрытым динамическим преобразованием), имеют возможность скрытой передачи контекста. А для вызова используют устаревшая конструкция ! без точки (с возможностью передачи некоторых аргументов без скобок).

Первоначально #-выражение использовалось только для определения Block/LambdaN

Эти структуры (типы) крайне не рекомендуется использовать в новом коде, поскольку они будут убираться в будущих версиях Libretto Из-за того, что скрытая передача контекста, вызов ! без точки и скрытое динамическое преобразования реализованы достаточно неинтуитивно и сложно.

Взамен можно использовать Func с типом Any*. Например, Func[Any*, Any*] вместо Lambda1, если не используется контекст.

А если нужен контекст, то передавать в явном виде через параметр, т.е. Func[Any, Any*, Any*] вместо Lambda1.

// устаревший вариант
def testOld(v: Lambda1) = {
  println(123.v!777)
}

// актуальный вариант
def testNew(v: Func[Any, Any*, Any*]) = {
  println(v.!(123, 777))
}

def main = {
  testOld: #(v: Any*){ $.string+", "+v }
  testNew: func: #(ctx: Any, v: Any*) { ctx.string+", "+v } // func можно убрать
}

Выдаёт

123, 777
123, 777

Если же нужно уточнение типов параметров, то использовать соответствующе типизированный Func/FuncN:

// устаревший вариант
def testOld(v: Lambda1) = {
  println(v!123)
}

// актуальный вариант
def testNew(v: Func[Int, Any*]) = {
  println(v.!(123))
}

def main = {
  testOld: #(v: Int){ v + 777 }
  testNew: func: #(v: Int){ v + 777 } // func можно убрать
}

Выдаёт:

900
900

Ещё в определении параметров методов можно использовать #-конструкцию. Это тоже устаревшая конструкция для передачи “по имени”, современным аналогом которой является ByName.

Вместо test(#v) можно использовать test(v: ByName[Any, Any*]), но вызывать переданную анонимную функцию другим способом:

// устаревший вариант
def testOld(#v) = {
  fix a = 123.v! // устаревший вызов
  println(a)
}

// актуальный вариант
def testNew(v: ByName[Any, Any*]) = {
  fix a = v.!(123) // актуальный вызов
  println(a)
}

def main = {
  testOld({println($); "abc"})
  testNew({println($); "abc"})
}

Выдаёт:

123
abc
123
abc

Вместо test(#: Int v) можно использовать test(v: ByName[Int, Any*]), но вызывать переданную анонимную функцию другим способом:

// устаревший вариант
def testOld(#: Int v) = {
  fix a = 123.v! // устаревший вызов
  println(a)
  println(type(a))
}

// актуальный вариант
def testNew(v: ByName[Int, Any*]) = {
  fix a = v.!(123) // актуальный вызов
  println(a)
  println(type(a))
}

def main = {
  testOld({$ + 1})
  testNew({$ + 1})
}

Выдаёт:

124
libretto/Any*
124
libretto/Any*

Но лучше вместо # в параметрах переходить на прямое использование Func/FuncN, поскольку ByName не является простой для понимания и использованию вещью.

// устаревший вариант
def testOld(#: Int v) = {
  fix a = 123.v! // устаревший вызов
  println(a)
  println(type(a))
}

// актуальный вариант
def testNew(v: Func[Int, Any*]) = {
  fix a = v.!(123) // актуальный вызов
  println(a)
  println(type(a))
}

def main = {
  testOld({$ + 1})
  testNew(#(v){v + 1})
}

Выдаёт:

124
libretto/Any*
124
libretto/Any*