Комментарии 11
Отсюда заполнения словарей через LINQ — автор кода явно пытался эмулироваться питоновские генераторы, хотя на C# это выглядит крайне неинтуитивно.
Отсюда же и проверка на is Tensor — в аналогичном методе в питоновской реализации return type неизвестен, потому что в коде Tensorflow нет статических тайп хинтов.
Пожалуй, в подобных проектах (где разработчикам приходится писать не на своём «естественном» языке программирования) статический анализ кода особенно важен, потому что помимо контроля качества кода он ещё и помогает разработчику выучить новую для него экосистему.
Это какая-то жесть. Как-будто пригнали питонистов писать на шарпе без подготовки.
Мало того что для словарей есть специальный инструмент LINQ
:
var producer_op_dict = producer_op_list.Op.ToDictionary(op => op.Name, op => op);
Вот эта запись просто убила:
var init_from_fn = initial_value.GetType().Name == "Func`1"; // <=
Кажется я первый раз вижу проверку типа по имени в не учебном, не тестовом коде. Непонятно что мешало написать:
var init_from_fn = initial_value?.GetType() is Type t
&& t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof(Func<>);
Можно проверить initial_value
на is Delegate
сначала, чтобы различить ицнициализацию по значению и с помощью функции.
Уточнение. При создании словаря второй аргумент не нужен:
var producer_op_dict = producer_op_list.Op.ToDictionary(op => op.Name);
Я пропустил вот эту строчку
init_from_fn ? (initial_value as Func<Tensor>)():initial_value,
По всей видимости, ожидается либо Func<Tensor>
, либо Tensor
. В таком случае подошел бы стандартный:
var initialValue = initial_value switch
{
Tensor tensorVal => tensorVal,
Func<Tensor> initializer => initializer(),
_ => throw new ArgumentException(nameof(initialValue))
};
На самом же деле нужен перегруженный метод, принимающиу Func<Tensor>
, вычисляющий его, и вызывающий метод, принимающий просто Tensor
, где и просходит вся работа.
Сложно представить сколько еще всего там просто так упаковывается/распаковывается и таскается в object
-ах. Расчитывать на какой-то перформанс в .NET
-части либы вообще не стоит.
А потом нам говорят что "статическая типизация не нужна", "с динамической типизацией проще, раз-раз и проект готов".
А потом нам говорят что «статическая типизация не нужна», «с динамической типизацией проще, раз-раз и проект готов».Динамическая типизация — мечта менеджера. Таски закрываются в три раза быстрее, а что их общее количество раз в десять больше — так зато можно вышестоящему менеджменту показывать, что вы делом заняты и красивые графики рисовать…
Не, я не против динамической типизации, сам пишу на R
, и это очень удобно для коротких проектов/высокоуровневых задач, когда вам нужно условно CSV.LoadData
, TensorFlow.MakeEverythingWork
. Но когда пишется большая либа/обертка к performance-critical бэкенду — тут хочется нормальной доменной модели, а не вот этих вот гаданий по строке, какой же тип прилетел к нам в object
.
Не, я не против динамической типизацииИзвините, но вы как раз против динамической типизации. Более того, подавляющее большинство людей, которые «топят» за динамическую типизацию — хотят вовсе не её.
тут хочется нормальной доменной модели, а не вот этих вот гаданий по строке, какой же тип прилетел к нам вНо ведь в этом — вся суть динамической типизации! Весь её смысл! Когда у вас в одной переменной может быть и число и строка и, я извиняюсь, Жопа-С-Ручкой!object
.
То, чего вы на самом деле хотите — это как раз статическая типизация… только без писанины. Ну вот как в Go:
s := "Hello, world"Статическая тут типизация или динамическая? Статическая, конечно. Ничего, кроме строки вы в
s
уже никогда не положите.Но объявлять тип перемнной тут не нужно — если его можно вычислить.
Так многие языки умеют. Даже C++ современный.
Просто динамически типизированные языки предоставляют такую возможность всегда… а языках со статической типизацией — есть ньюансы.
Но это — именно причина из-за которой Роб Пайк, внезапно, обнаружил, что люди активно переходят с Python на Go, а с C++… не очень.
Забавно, кстати, что современный Python обзавёлся-таки типами — что и показывает, что даже большинству людей, использующих его хочется-таки статической типизации.
За всех не скажу, но я хочу не "статическую типизацию без писанины", а нечто другое. Я и сейчас могу написать var s = "Hello, world!";
, другое дело что в текущем скоупе (области видимости) s
может содержать инстанс типа string
или наследуемого типа (если таковые имеются), а не, внезапно, (int)42
.
Для меня статическая типизация это в первую очередь контракт. Если у меня есть int GetStrLength(string @string)
, и я его вызову используя переменную s
(var len = GetStrLength(s);
), я асболютно уверен, что внутрь функции я передам либо строку, либо null
, а из функции вернется знаковое целое размером 4 байта; или все это упадет с исключением. Более того, не ломая CLR
, без грязных трюков это ограничение обойти невозможно (или мне неизвестно как). Именно ради этих контрактов и строятся все эти слоищи абстракций и тратится столько времени по сравнению с разработкой на языке с динамической типизацией.
тут хочется нормальной доменной модели, а не вот этих вот гаданий по строке, какой же тип прилетел к нам в object.Но ведь в этом — вся суть динамической типизации! Весь её смысл! Когда у вас в одной переменной может быть и число и строка и, я извиняюсь, Жопа-С-Ручкой!
И это снова контракт, который всего лишь означает, что в compile-time допускается вызов этого метода с аргументом любого типа. И такой контракт используется повсеместно, например, в обработке событий. Легко представить типичный обработчик вида void EventFired(object sender, EventArgs e)
. И если sender
у вас может быть любой, то подписаться на событие, где вторым аргументом передается не каноничный EventArgs
, а, например, строка — уже не получится. И об этом вы узнаете в момент написания строчки кода в IDE или в момент компиляции — благодаря статической проверке типов. В случае же с динамической, узнаете вы об этом печальном type mismatch в продакшене, когда вам в метод прилетит строка, и вы попытаетесь вызвать на ней метод, доступный только на EventArgs
.
Справедливости ради, в C#
есть "настоящая" динамическая типизация, и это dynamic
, который на самом деле object
, но с дополнительными инструментами.
Предупреждение анализатора: V3051 An excessive type check. The object is already of the 'Tensor' type. array_grad.cs 154
Если он null, то он не Tensor (если это не структура).
Как странный код скрывает ошибки? Анализ TensorFlow.NET