
Комментарии 119
Вы что как ребенок, никакого скандала не будет. Скандал разгорается только тогда это группа людей голосует за демпартию.
пока не разгорелся очередной скандал связанный с дискриминацией людей с фамилиями
Вот если бы она была темнокожей, то да… А так — тьфу, полгода никто так и не пошевелился.
Надо девушке выйти замуж за парня с фамилией False.
PS: Языки без строгой типизации лучше говорили они…
Там скорее всего дело не в типизации, а в валидаторе значений.
Просто так не получится — кроме фамилии Total у него и имя должно быть Value!
:)
«Запрещается запись имени ребенка, которое состоит из цифр, буквенно-цифровых обозначений, числительных, символов и не являющихся буквами знаков, за исключением знака „дефис“, или их любой комбинации либо содержит бранные слова, указания на ранги, должности, титулы», — так звучат изменения в статью 18 закона «Об актах гражданского состояния»
Так что в Сумму Итого вполне себе можно переименоваться. Причем судя по всему есть баг, что это относится к имени ребенка при рождении, а в дальнейшем случаются и должности в имени например «Президент России Викторовна»
lenta.ru/news/2021/02/20/prezident_rossii
— Конечно. Как Вас зовут сейчас?
— Пётр Говно.
— О, понятно. А на что хотите поменять?
— Хочу быть Виталиком…
На Хабре все время приводят тупой вариант, где мама говорит «Да, мы зовем его Робин-Брось-Таблицу» — а что, нормальное же имя, как для переводчика?
Вот, собственно:

Может и тупо, но с "Дропика" я кринжанул далеко не так сильно, как с Робина. Глобализация, все дела, заимствования вроде "Эдвард-руки-ножницы" и «Двейн "Скала" Джонсон» уже не так сильно смущают, а вот чудаковатое "Дропик" — это откровенно грустно. Да и в целом перевод с xkcd.ru выглядит профессиональней.
Она ещё хорошо отделалась. А вот если бы где-то в гос. учреждении, или в банке — беда, пиши пропало.
Надо было кириллическую е использовать, да и всё
Вряд ли, со слабой динамической типизацией она просто на каком-то шаге стала бы "Rachel 1".
Это фамилия, тут вообще на всех шагах должна быть строка, поэтому видимо дело в протоколе обмена. В JSON логические значения по синтаксису отличаются от строк, скорее всего у них там кривой парсинг XML.
<IsVerified>True</IsVerified>
<LastName>True</LastName>
Вроде бы через XSD это как-то решается.
скорее всего у них там кривой парсинг XML.
Ну, вообще в XML только строки и ничего более. И при парсинге надо приводить текст ноды к желаемому типу. Т.е. программист должен заранее знать, что нода с именем IsVerified — хранит булево значение, а LastName — строковое.
Это если у вас статическая типизация, и вы каждую схему вручную обрабатываете. А с динамической типизацией можно сделать универсальную функцию parseXml(), которая будет true/false парсить в bool, числа в int, а все остальное в строку, и складывать в ассоциативный map "название поля — значение". Видимо они так и сделали, возможно для совместимости с JSON.
В статью скриншот добавили, ошибка еще глупее оказалась, там специальная проверка на строку "true".
Можно, но это сложнее, и вы не сможете просто писать string name = xmlObject.name; bool isVerified = xmlObject.isVerified;
Что-то типа такого.
<?php
declare(strict_types=1);
function parseXml(string $xml)
{
$xmlObj = new stdClass();
$xml = trim($xml);
preg_match('#^\<(\w*)\>#smu', $xml, $matches);
$rootName = $matches[1];
preg_match("#^\\<{$rootName}\\>(.*)\\<\\/{$rootName}\\>#smu", $xml, $matches);
$content = trim($matches[1]);
while (true) {
preg_match('#^\<(\w*)\>#smu', $content, $matches);
$elementName = $matches[1];
preg_match("#^\\<{$elementName}\\>(.*)\\<\\/{$elementName}\\>#smu", $content, $matches);
$value = trim($matches[1]);
if (preg_match('#^\d+$#', $value)) {
$value = (int)$value;
} elseif (preg_match('#^true|false$#', $value)) {
$value = ($value === 'true' ? true : false);
}
$xmlObj->$elementName = $value;
$content = trim(substr($content, strlen($matches[0])));
if ($content === '') break;
}
return $xmlObj;
}
$xml = '
<root>
<id>123</id>
<firstName>test</firstName>
<lastName>true</lastName>
<isVerified>true</isVerified>
</root>
';
$xmlObj = parseXml($xml);
var_dump($xmlObj);
/*
class stdClass#1 (4) {
public $id => int(123)
public $firstName => string(4) "test"
public $lastName => bool(true)
public $isVerified => bool(true)
}
*/
class User
{
public string $lastName;
public bool $isVerified;
}
$user = new User();
$user->isVerified = $xmlObj->isVerified;
$user->lastName = $xmlObj->lastName;
// PHP Fatal error: Uncaught TypeError: Typed property User::$lastName must be string, bool usedНу да, и? PHP это язык с динамической типизацией, тип существует в рантайме вместе со значением переменной. Поэтому можно создать произвольный xmlObject, не описывая его предварительно специальным классом, и свойства у него будут иметь разный тип. То есть программист не "должен заранее знать, что нода с именем IsVerified — хранит булево значение, а LastName — строковое", и он может написать универсальную функцию для парсинга произвольного XML. А дальше уже ее результаты можно использовать в коде, где есть контроль типов.
Ну так и в языке со статической типизацией у вас будет что-то такое
Ну напишите что-то такое на C++, C# или Java.
data Node = TextNode Text | NumberNode Number | CDataNode BlobА где тут string, int и boolean, чтобы можно было задавать значения полям класса с такими типами?
И вы как-то реализацию parseXML многозначительно за многоточием спрятали, и вообще она у вас не используется.
я могу в своём менее выразительном хаскеле написать
A.FromJSON
Угу, когда за вас функцию произвольного парсинга уже кто-то написал, конечно ее писать не надо) Но мы-то говорим о ее реализации.
MyData { lastName :: String, isVerified :: Bool }Но это, как я понимаю, и есть описанный предварительно специальный класс. В моем примере класс User нужен просто для демонстрации, без него парсинг тоже нормально работает. Вместо него $xmlObj->lastName можно было передать в функцию, принимающую string.
Ну, если серьёзно, зачем выбирать языки с недостаточно выразительной системой типов?
Потому что когда я сказал "Это если у вас статическая типизация, и вы каждую схему вручную обрабатываете", я подразумевал наиболее распространенные. То есть те, в которых утверждение "при парсинге надо приводить текст ноды к желаемому типу и программист должен заранее знать", на которое я отвечал, верно. В них оно верно именно из-за статической типизации, потому что настолько же или даже менее выразительная динамическая дает возможность такую функцию написать.
Ну вместо String там Text, например.
А, ок, я подумал, что TextNode это тип, а Text это название поля.
А вот дальше вы проверяете конкретный тип конкретной ноды в конкретном контексте, который вам нужен
Ну а в моем примере не надо проверять, в том и смысл.
Такие проверки
case (findNode "foo/bar", findNode "baz/quux") of
(Just (NumberNode n1), Just (NumberNode n2)) -> Just (n1 + n2)это и есть "можно, но это сложнее", и вы не можете просто писать
int sum = findNode(xml, "foo/bar") + findNode(xml, "baz/quux").
В C++ будут такие же проверки типа ноды
if (node1->type == TYPE_NUMBER && node2->type == TYPE_NUMBER) sum = (*(int*)node1->pValue) + (*(int*)node2->pValue);.
Я именно их и подразумевал. И поэтому проще заранее знать "какие ноды что хранят" и "приводить текст ноды к желаемому типу" из строки по месту
int sum = toInt(xml->getNodeValue("foo/bar")) + toInt(xml->getNodeValue("baz/quux")).
Так в том и суть: её написать можно, даже в языке со статической типизацией,
Такую, чтобы не писать везде "case of Just NumberNode" нельзя. В том и была суть. Такие проверки это фактически и есть реализация динамической типизации.
Это не "парсить в int/string/bool и складывать в ассоциативный map", а "парсить в NodeType и складывать в ассоциативный map<string, NodeType>". Со вторым я и не спорил, что это возможно.
это ж не предоставляемый компилятором интринсик.
В данном случае компилятором предоставляется система типов, которая немного упрощает ее написание по сравнению с другими языками со статической типизацией.
Да, и при этом в компилтайме вы не узнаете, что вы делаете ерунду.
В вашем коде проверка case of NumberNode выполняется в рантайме, так же как и в PHP. В плане проверки типов тут вообще разницы нет. Она будет только если lastName будет иметь тип, отличный от string | int | bool, тогда да, в Haskell компилятор скажет, что такого типа нет в списке возможных типов ноды, поэтому присвоить значение нельзя. Но мы же не об этом случае говорим.
либо у вас такое место встречается больше одного раза, и тогда вы пишете тип данных вроде того, что выше
Ну вот в PHP его можно не писать, и все равно иметь проверки типов во всех местах использования.
Так это вроде не противоречит моему исходному тезису, разве нет?
Я написал "А с динамической типизацией можно сделать универсальную функцию parseXml()", вы на это возразили, что и со статической можно. Но со статической именно в таком виде сделать нельзя, тем более в мейнстримных языках, хотя можно сделать в другом, чтобы работало так же. "Можно" в моем высказывании можно читать как "гораздо проще". Так-то понятно, что динамический PHP написан на статическом C, и значит принципиальная возможность есть, просто код, который надо писать программисту, отличается.
Но вы там явно расставляете аннотации string/bool/etc, разве нет?
Ну да, проверка типов же подразумевает что типы указаны в 2 местах, и мы их сравниваем. Только писать "тип данных вроде того, что выше" не нужно, объектом такого типа данных является сам xmlObject. Никакого объединенного типа NodeType = string|int|bool в коде программиста не существует, он работает сразу с конкретными типами.
можно написать несколько функций типаasString :: Node -> Maybe Text
isVerified <- asBool =<< findNode "baz/quux" xml
Это и есть "при парсинге надо приводить текст ноды к желаемому типу. Т.е. программист должен заранее знать, что нода с именем IsVerified — хранит булево значение, а LastName — строковое".
Чем она плоха?
Тем, что тип значений не string или bool, а NodeType, который type union всех возможных, и поэтому конкретный тип надо проверять вручную через case of.
Я же говорил не о том, что парсить XML со статической типизацией вообще невозможно, а что нельзя это сделать так же просто и наглядно, как с динамической.
Давайте сделаем более конкретно, а то я не очень понимаю, что вы имеете в виду. Возьмем JSON, с ним попроще. Вот есть работающий код на PHP.
declare(strict_types=1);
class User {
public string $lastName;
}
function checkLastName(string $lastName) {
return true;
}
function run(object $jsonObj) {
$user = new User();
$user->lastName = $jsonObj->lastName;
checkLastName($jsonObj->lastName);
}
function parseJson(string $json): object {
return json_decode($json);
}
$json = '{
"id": 123,
"firstName": "test",
"lastName": true,
"isVerified": true
}';
$jsonObj = parseJson($json);
run($jsonObj);
// TypeError: Typed property User::$lastName must be string, bool used Напишите полностью аналогичный код на Haskell. Критерии — parseJson() возвращает объект, он передается в другую функцию, его свойство используется и при установке свойства в объекте User, и при передаче в функцию checkLastName(), без повторного парсинга или объявления промежуточного класса с известной структурой. Структура User отличается от структуры JSON, а ошибка из статьи воспроизводится, так как в JSON lastName имеет тип bool. До checkLastName() в этом коде выполнение не доходит, но если закомментировать предыдущую строчку, там тоже будет ошибка типов.
Так будет проще сравнить объем кода и где какие проверки.
попытаться проинтерпретировать ноду как строку, а, если не получится, как дату
Как вы это сделаете на php?
Так в PHP не надо это делать, в дереве xml уже готовые для использования типы, а не обобщенный NodeType. Я не очень понял почему нода может быть не строкой, если в xml изначально все значения тегов строковые, но если вы подразумеваете, что там после разбора будет int timestamp, который можно конвертировать в дату, то на PHP будет такая же проверка типов.
$value = is_string($xml->quux->bar) ? $xml->quux->bar : (new DateTime('@' . $xml->quux->bar))->format('Y-m-d H:i:s');Реализация findNode для конкретного значения ничем не отличается от задания специального класса-схемы с геттером, я и говорю, что в PHP это не нужно.
Именно что не при парсинге, а после.
Ну в той ситуации в коде будут всегда строковые значения, которые надо конвертировать по месту к нужному типу, а у вас в коде обобщенный NodeType, из которого вы в коде достаете по месту нужный тип. Для программиста разницы нет, хотя в рантайме значения отличаются. Мой изначальный коммент как раз и был про то, что программисту надо вручную доставать нужный тип.
Что не отличается от соответствующего знания вашего php-программиста в момент написания класса User.
Отличается. В момент написания класса User вообще может еще не быть никакой работы с XML. В том утверждении речь идет про ноды в XML, а не про свойства класса. И класс User не нужен, я могу просто сделать var_dump(), и он покажет, что в одном свойстве string, а в другом bool.
В ином же случае я не понимаю претензии, потому что у вас там тоже в каком-то смысле юнион, просто он скрыт от программиста.
Так в том и смысл. Технические детали скрыты от программиста, так же как машинные команды или счетчик в foreach ($list as $element). Зачем мне работать с обобщенным NodeType, если мне нужны строки и инты. Язык с динамической типизацией скрывает детали реализации, которые со статической программист пишет сам.
В самом деле, зачем вам в вашем клиентском (для библиотеки) коде сначала руками парсить XML или жсон в какой-то объект, потом руками из него что-то доставать, если можно сразу распарсить в нужную структуру?
Затем что не всегда в точке парсинга есть нужная структура, а в точке использования структуры зависимость для парсинга. И если так делать, то слишком много зависимостей по коду надо раскидывать. А так у нас в место использования передается ассоциативный массив, который вы можете хоть парсингом XML получить, хоть парсингом JSON, хоть вручную в тестах захардкодить.
Тут я сразу сдаюсь: ошибка типов там будет (если их не проверять) независимо от комментирования предыдущей строчки.
Это было просто пояснение про работу этого кода. Но я не понимаю, что вы имеете в виду. У вас точно так же ошибка возникает в рантайме, когда вы запускаете parseJson json >>= run "lastName", и выдает только ошибку про первую строчку Left "key lastName has unexpected type".
lastName <- maybeToRight "key not found or has wrong type" $ obj ^? key keyName . _StringНу вот вы и нарушили критерий "его свойство используется и при установке свойства в объекте User, и при передаче в функцию checkLastName()". Вы используете не свойство объекта, а промежуточную переменную. Причем сделали кастинг к заранее известному типу string, это нарушает другой критерий "без объявления промежуточного класса с известной структурой". Формально это не класс конечно, а можно сказать только одно поле, но принципиально это ничего не меняет.
Полный эквивалент был бы такой.
let user = User (obj ^? key keyName)
pure $ checkLastName (obj ^? key keyName)Вот как раз про это я и говорил, что в языках со статической типизацией так написать нельзя.
lastName <- maybeToRight [i|key #{keyName} has unexpected type|] $ lastNameObj ^? _StringТак это ж проверка типа вручную, которую по условиям надо было избежать. С сильной динамической типизацией это делает сама система типизации.
Ну так я ж говорю, я не говорил, что принципиально невозможно написать какую-то обобщенную функцию парсинга, я имел в виду, что нельзя написать именно такую и пользоваться ей именно так, как в языках с динамической типизацией.
В целом да, только надо учитывать, что один string это тип, а другой string функция кастинга. Больше сущностей, с которыми надо работать программисту. И сам подход отличается, мы проверяем сами, а не полагаемся на автоматическую проверку типов.
Ну и саму реализацию функции парсинга можно отметить. Со статической типизацией ее объем будет гораздо больше.
В C++ будут такие же проверки типа ноды
if (node1->type == TYPE_NUMBER && node2->type == TYPE_NUMBER) sum = (*(int*)node1->pValue) + (*(int*)node2->pValue);.
Я именно их и подразумевал. И поэтому проще заранее знать «какие ноды что хранят» и «приводить текст ноды к желаемому типу» из строки по месту
int sum = toInt(xml->getNodeValue(«foo/bar»)) + toInt(xml->getNodeValue(«baz/quux»)).
В c++ это тоже реализуется елементрано. Достаточно лишь немного углубиться в ООП.
Например: создаём абстрактный класс Node, с множеством методов:
asString, asBool, asInt, и так далее.
Далле создаём наследуемые классы для каждого типа данных (StringNode, BoolNode,...), и в них реализовываем преобразования в соответствующих методах. Если преобразовать указаную ноду в тот или иной тип невозможно, то посылаем исключение. В результате вышеописаный код можно изобразить так:
try{
int sum = node1->asInt() + node2->asInt();
...
}catch(...){
cout << "Type error";
}
Кто-то в шутку сказал, что самым быстрым решением для Рэйчел будет выйти замуж и взять фамилию супруга, но предостерегли, что могут быть проблемы, если у супруга будет фамилия «Null» или «Drop Table».
ох уж этот бородатый юмор))
Рэйчел пояснила, что связывалась множество раз с техподдержкой Apple, но специалисты компании никак не могли ей помочь в данной ситуации, хотя оплата за выбранный ранее тариф в iCloud снимается с банковской карточки ежемесячно, а ее учетная запись не заблокирована.
Интересно, а почему она связывалась с представителями Apple, а не с представителями суда? Деньги снимают, но услугу не оказывают. Ладно у нас судиться не любят и не хотят, а там-то… Глядишь, после иска сразу и баг бы нашли, и починили бы в момент.
У Apple много очень-очень хороших юристов, и хитрые лицензионные соглашения, написанные этими хорошими юристами. Так что это реально лотерея, и в случае проигрыша судебные издержки останутся на истце.
Интересно, а почему она связывалась с представителями Apple, а не с представителями суда?
Потому что в суде Вас спросят связывались-ли Вы с техподдержкой для устранения ошибки и возврата денег за не оказанную услугу.
На всякие суды уйдёт куча времени и нервов, а выхлоп будет пара десятков баксов, которые она до этого заплатила. Хотя там всё решится до суда выплатой компенсации. Но время всё равно потратишь. Проще связаться с ними.
Эппл иногда реально пугает. С одной стороны, фокус на безопасность и конфеденциальность, с другой — такие детские ошибки.
Да, ошибка реально детская. Что за индусы там код ваяли?
createFromResponse класса AuthenticatedUserDetails, который собственно, создает объект из данных реквеста, копируя из него определенные поля, указанные в f и m (dsid, lastname, firstname, и т.п.). И возращает этот новый объект.Собственно все поля успешно присваиваются полем, кроме особого случая, когда эта поле равно строке
'true' (тогда присвоить true)."true" строго сравнивается со строкой "True". Вроде, никакого .toLowerCase() там нет… Похоже, что ошибка не в этом месте.Type error: cannot set value ‘true’ to property ‘lastName‘Вот совсем не очевидно — буквально вчера очепятался в yml для пайплайна гитлаба, вместо reports:junit: написал reports:jUnit:. В ошибке получил "неопознанный ключ 'junit'"
Это показывает то, что поддержка в Эппл находится в таком состоянии, что любая нестандартная незаскриптованная проблема, особенно единичная просто не может найти свой путь к разработчикам. И это проблема не только Эппл.
Думаешь что в другой линии сидят люди с высокой квалификацией?) Или вопросы сильно отличаются?)А какой иначе в них смысл? Квалификация каждой линии должна быть достаточной, чтобы решать, передавать ли вопрос в следующую линию.
Ещё раз ни один нормальный инженер не будет работать на поддержке в любом её виде. Если такой попадается это скорее исключение чем правило. А не инженер будет подобные вопросы игнорить и заруливать на шаблоны ответов. При этом совершенно искренне не понимая «А что он докопался»Инженер не должен «сидеть в техподдержке» в смысле разговора с пользователями. Задача техподдержки — оформить багрепорт для решения проблемы инженером. И не знаю, где и кем вы работали, но всю мою карьеру разработчика мне регулярно приходится заниматься багами, заведёнными техподдержкой по факту обращений пользователей.
t[o] = "true" ...?
Если яблочники этого не понимают то это очень печально.
Напомнило фильм Идиократия, где одному парню присвоили имя You Sure .

Обладательница фамилии True полгода не может воспользоваться своим аккаунтом в Apple iCloud