thedeemon: (office)
[personal profile] thedeemon
Ребе [livejournal.com profile] metaclass уже не первый раз поднимает эту тему: можно ли иметь строгую типизацию записей, но не объявляя их заранее? Вот пара примеров из используемых мною языков.

Первый пример: Haxe.
function makeData()
{
  return { a: 99, b : " bottles of beer" };
}
	
function useData(data):Void
{
  var x:Int = data.a;
  var y:String = data.b;
  trace(x, y);
}	

...
var t = makeData();
useData(t);

Язык со статической типизацией. Где типы не указаны, компилятор сам их выводит. Тут функция makeData производит значение анонимного типа с парой полей типа Int и String (тоже выведены). Другая функция использует данные из такой записи. Напрямую одна другую даже не вызывает. Все компиляется и работает гладко. Теперь если заменить строчку
var y:String = data.b;
на
var y:String = data.c;
то компилятор скажет:
C:\vc\player\src/Main.hx:876: characters 10-11 : { b : String, a : Int } should be { c : String, a : Int }
C:\vc\player\src/Main.hx:876: characters 10-11 : { b : String, a : Int } has no field c
C:\vc\player\src/Main.hx:876: characters 10-11 : For function argument 'data'

А если там поставить
var y:Bool = data.b;
то скажет
C:\vc\player\src/Main.hx:876: characters 10-11 : { b : String, a : Int } should be { b : Bool, a : Int }
C:\vc\player\src/Main.hx:876: characters 10-11 : Invalid type for field b :
C:\vc\player\src/Main.hx:876: characters 10-11 : String should be Bool
C:\vc\player\src/Main.hx:876: characters 10-11 : For function argument 'data'

Т.е. как раз мечтаемое: тип заранее не описываем, он выводится на месте описания данных, и все статически проверяется при использовании.

Второй пример: D.
Аналогичный код:
auto makeData()
{
  Tuple!(int, "a", string, "b") data = tuple(99, " bottles of beer");
  return data;
}

void useData(T)(T data)
{
  int x = data.a;
  string y = data.b;
  writeln(x,y);
}
...
auto t = makeData();
useData(t);

Чуть длиннее, но ненамного. Причем вместо tuple(99... можно было сразу писать data.a = 99;... Кстати, здесь конструктор типов Tuple и функция tuple - не ключевые слова языка, а чисто библиотечные штуки, входят в стандартную библиотеку.
В таком виде все компиляется гладко. Меняем
string y = data.b;
на
string y = data.с;
Компилятор отвечает "Error: no property 'c' for tuple '(int, string)'".
Если же поставить
bool y = data.b;
то говорит "Error: cannot implicitly convert expression (data._field_field_1) of type string to bool.

В общем, в приличных языках счастье есть, и даже без макросов. Ну а динамическая типизация для таких задач не нужна и даже вредна.

Date: 2013-02-23 08:53 pm (UTC)
From: [identity profile] si14.livejournal.com
Меня не покидает ощущения, что вы и metaclass говорите о немного разных проблемах. Его проблема — то, что термы летают непонятно как по программе и ошибка может произойти где-то в глубине колл-стека; решение этой проблемы может лежать в плоскости статических гарантий, но это лишь один из вариантов. Вы же априори считаете, что статические гарантии единственно правильный путь (или мне так кажется) и пытаетесь в рамках этой модели решить проблему metaclass'а. Есть подозрение, что она так не решается; пример с БД есть подтверждение этому. Более того, я не уверен, что для решения изначальной проблемы вообще нужен статический анализ; например, мы можем прицепить к каждому терму метадату с его «историей» (оставим пока вопросы реализации и потребления памяти); тогда в случае возникновения ошибки вида «достали из словаря поле foo и попытались сложить его с 3, но оно оказалось строкой» можно выяснить, в каком же именно месте в него положили строку (что-то такое было в Racket, если мне не изменяет память). Насколько я понимаю, это решило бы проблему metaclass'а, но не имело бы ничего общего с «выводим всё в компайлтайме».

Date: 2013-02-23 08:56 pm (UTC)
From: [identity profile] si14.livejournal.com
Там чуть выше ещё пробегала прекрасная мысль — типы с предикатами. Проблема только в том, что в идеале эти предикаты должны быть не над типами, а над термами; т.к. нормально в компайлтайме задача работы с этими предикатами не разрешима, стоило бы отложить её до рантайма и *попытаться* (хотя бы частично) что-то выводить в компайлтайме (вроде dialyzer'овского success typing). Но я не знаю таких конструкций в реальных языках.

Date: 2013-02-24 06:13 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Предикат над термами и есть тип.

Date: 2013-02-24 07:48 am (UTC)
From: [identity profile] si14.livejournal.com
Ну, да. Однако то, что это можно назвать зависимыми типами, не меняет остальной части комментария.

Date: 2013-02-24 08:57 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Если какие-то штуки в статике сделать слишком сложно или даже вовсе не получается, то их действительно можно и нужно делать в рантайме, я совсем не против. Однако если что-то делается в статических типах очень просто (как в посте), то я не вижу причин этим не пользоваться и откладывать обработку ошибок в рантайм.

Date: 2013-02-24 06:13 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Ребе много разных проблем упоминает, я тут не берусь решать все, а лишь одну, упоминавшуюся им и ранее: возможность, не объявляя по классу на каждый чих, слепить по месту запись (набор именованных и типизированных полей), а в другом месте ее использовать, при этом имея привычные статические гарантии, вроде того, что мы не обратимся к несуществующему полю и не получим массив вместо числа.

Date: 2013-02-24 08:12 am (UTC)
From: [identity profile] si14.livejournal.com
Я правильно понимаю, что при этом имя поле не может быть произвольным термом?

Date: 2013-02-24 08:54 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Я не понял вопроса.

Date: 2013-02-24 06:46 pm (UTC)
From: [identity profile] si14.livejournal.com
foo[getThisFieldNameFromDatabaseByAstralKey("bar")] = 1.

Date: 2013-02-24 07:11 pm (UTC)
From: [identity profile] thedeemon.livejournal.com
А, да, имя поля просто идентификатор, известный во время компиляции. Забудьте уже про БД.

Date: 2013-02-24 08:45 pm (UTC)
From: [identity profile] si14.livejournal.com
Вот я про это и говорю — вы взяли конкретное подмножество проблемы и показали, как изящно решить его статическими типами. Однако это не решение проблемы в целом, с одной стороны, и даже не облегчение её в частности с другой — потому что гарантии идут вместе с этим самым требованием известности имён полей при компиляции.

Date: 2013-02-25 03:56 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Это не подмножество. Это вполне самостоятельная проблема, не связанная с тем, что вы пытаетесь додумывать.

Скажу больше: известность полей при компиляции - это как раз норма. Единственный софт, где поля при компиляции могут быть неизвестны, это обслуживающие БД утилиты вроде PhpMyAdmin или SQL Management Studio. В прикладном софте поля должны быть известны, иначе это хаос, ад, коровники, стыд и скрам.
Edited Date: 2013-02-25 04:02 am (UTC)

Date: 2013-02-25 04:10 am (UTC)
From: [identity profile] si14.livejournal.com
Я не пытаюсь додумать; я испытываю боль, схожую (как я понимаю) с болью metaclass и пытаюсь её формализовать :)

Спорное утверждение. Как минимум я бы предпочёл не перезапускать свой серверный софт на каждое изменение схемы.

Date: 2013-02-25 08:11 am (UTC)
From: [identity profile] thedeemon.livejournal.com
А я бы еще предпочел, чтобы он без перезапуска и моего вмешательства сам менялся под меняющиеся требования клиентов. :)

Имхо, схему следует считать кодом, а не данными. Так же как типы мы считаем частью кода. БД следует считать одним из модулей приложения. Если меняется схема, это эквивалентно тому, что в программе поменялся один из модулей, изменились типы в нем. Обычным следстивем должна быть пересборка и перепроверка всех модулей, зависящих от изменившегося.

Date: 2013-02-25 09:46 am (UTC)
From: [identity profile] si14.livejournal.com
Шутки шутками, а это всё давно уже работает именно в таком виде (изменение схемы без перезапуска) у Ericsson'а в Erlang'е или у Столлмена в Емаксе. Равно как и изменение кода. Отказ от работы с живой системой, а не деревянным буратино — шаг назад.

Date: 2013-02-25 10:31 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Это все равно в первую очередь изменение кода, разница лишь в способе ввода нового кода в систему - с полной ее перезагрузкой или частичной или даже плавным замещением. Да, такие трюки бывают, и изредка они даже нужны и оправданы. Акробаты в цирке и не такое показывают.

Date: 2013-02-25 08:15 pm (UTC)
From: [identity profile] thinker8086.livejournal.com
>> А я бы еще предпочел

Приблизительно в этот момент програмисты перестанут быть нужны, я полагаю.

Date: 2013-03-07 09:46 am (UTC)
From: [identity profile] sassa-nf.livejournal.com
всё в наших руках. нужно перестать писать программы, которые будут выполнять требования заказчика без программиста.

Date: 2013-03-07 09:53 am (UTC)
From: [identity profile] sassa-nf.livejournal.com
Я думаю, есть целая куча софта, где поля не известны при компиляции. Вспомнить сериализацию - у всех времён, народов и языков сериализация предполагает асинхронность изменений кода и сериализованных объектов. Здесь не получится даже "перезапустить" систему.

Но напрашивается существование сильного утверждения о полиморфизме такого кода - сами сериализаторы-десериализаторы не могут зависеть от ими десериализуемой структуры.

Profile

thedeemon: (Default)
Dmitry Popov

December 2025

S M T W T F S
 12 3456
789101112 13
14151617181920
21222324252627
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 25th, 2026 11:24 am
Powered by Dreamwidth Studios