Устаревшие типы (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*