LINUX.ORG.RU

[scala] Dependent types?

 


0

2

Есть класс Column:

class Column(val name: String) {
  type Type
}

Хочу сделать класс Cell такой, что в конструктор можно передать экземпляр класса Column и значение того типа, который в конкретном экземпляре определен, например так:

val cl1 = new Column("id") { type Type = Int }
val cl2 = new Column("name") { type Type = String }
val c1 = new Cell(cl1, 1)
val c2 = new Cell(cl2, "Vasya")

При попытке определить его как

class Cell(val column: Column, val value: column.Type)
- ругается, что not found: object column (оно и понятно). Вариант
class Cell(val column: Column, val value: Сolumn#Type)
прокатывает, но тогда при попытке сделать
val cl = new Column("id") { type Type = Int }
val c = new Cell(cl, 1)
ругается, что
type mismatch;
[error]  found   : Int(1)
[error]  required: org.ovk.picoerp.Column#Type

Вообще так можно сделать или я хочу странного?

★★★

По-моему хочешь странного. Я бы разместил класс Cell внутри Column. Тогда тип Type схватывался бы автоматически. По сути Type работал бы как параметр типа Cell. Ведь ты этого добиваешься?

dave ★★★★★
()

Может, сделать val value: Any, а тип определять в конструкторе?

note173 ★★★★★
()

А почему бы просто не параметризовать Column[T] и Cell[T] по типу T? Понимаю, что тип как член концептуально мощнее обычной параметризации, но тогда будут непонятки с типом Cell, с которыми ты уже столкнулся.

dave ★★★★★
()
Ответ на: комментарий от dave

> Я бы разместил класс Cell внутри Column.

Да, так конечно было бы клево, но это неправильно - Column по замыслу содержит описание n-й колонки таблицы, а Cell - n-ю ячейку данной строки и входит скорее иннерклассом в класс Row.

А почему бы просто не параметризовать Column[T] и Cell[T] по типу T?


А как тогда заставить компилятор статически проверять, что в конкретном cells(i): Cell[T] этот T именно тот, что и в соответствующем columns(i): Column[T] ?

ovk48 ★★★
() автор топика
Ответ на: комментарий от ovk48

> А как тогда заставить компилятор статически проверять, что в конкретном cells(i): Cell[T] этот T именно тот, что и в соответствующем columns(i): Column[T] ?

Можем нарваться на type erasure? Да, можем. А как еще придумаешь? Пока не вижу вариантов.

dave ★★★★★
()
Ответ на: комментарий от ovk48
class Column[T]

class Cell[T](column: Column[T], value: T)

object Test {

  val column = new Column[Int]
  val cell = new Cell(column, 10)

  val wrongCell = new Cell(column, 10.0) // ERROR

  def main(args: Array[String]) {}
}
dave ★★★★★
()
Ответ на: комментарий от dave

Да, это конечно классно работает, я по-моему так сначала и сделал. Но мне еще надо сделать Set таких колонок. И если сказать

var _columns = Set[Column[_]]()
а потом
new Cell(column, 2)
то оно ругается, что
type mismatch;
[error]  found   : org.ovk.picoerp.Column[Int]
[error]  required: org.ovk.picoerp.Column[Any]
Приходится писать
new Cell[Int](column, 2)
и этот Int тут сильно неудобен. Хотелось бы, чтобы Int выводился из типа значения column.

ovk48 ★★★
() автор топика
Ответ на: комментарий от ovk48

Написать метод apply для объекта-компаньона? Тогда тип будет выводится.

class Cell[T] {..}

object Cell {
  def apply[T](column: Column[T], value: T): Cell[T] = new Cell[T](column, value) 
}
dave ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.