Никак не могу придумать случай, когда вообще может понадобиться динамическая типизация...
Динамическая типизация есть везде. Например, ты можешь сложить int и float, хотя это разные типы с разным представлением. И в зависимости от порядка сложения, ты получишь на выходе или int, или float - это даже породило отвратительный паттерн типа *1.0
Это ты про строгую или слабую типизацию, например в Си, как ты сказал можно сложить int и float, благодаря безопасному согласованию типов и положить в long если хочешь.
А динамическая это когда ты вначале обьявил int a = 0, а потом a = "test string" и всё ок, теперь а - строка.
А динамическая это когда ты вначале обьявил int a = 0, а потом a = "test string" и всё ок, теперь а - строка.
И я о том же. Мне вот за "любителем" динамической типизации приходится говно разгребать... то был массив как массив, а нет, он как парижская мадемуазель то стринг, то инт.
В Си для этого есть указатели, которые могут указывать на все, что тебе вздумается и никакой проверки в рантайме ни на что нет.
не во всех. В некоторых современных языках такого нет - например в swift ты даже не сможешь Float и CGFloat сложить, не то что Int.
Пример языка, где её нет — Rust (playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=add5e25b9528a67015330258eab4c504 ).
Запрещено:
1 + 0.1 — складывать целое с дробным
1u32 + 1u16 и 1.0f32 + 1.0f64 — типы разной ширины
let z: *const u32 = &8u16 — присваивать указатели или ссылки разных типов (ссылка в указатель того же типа — разрешено, обратно — запрещено, т.к. ссылка, в отличие от указателя, не может быть нулевой)
Тем не менее, можно писать 1 as _ + 0.1 as _ — тогда компилятор преобразует типы в какой-то общий, но только при условии, что подходит только один тип, иначе ошибка автовыведения.
Запрещено:
1 + 0.1 — складывать целое с дробным
1u32 + 1u16 и 1.0f32 + 1.0f64 — типы разной ширины
let z: *const u32 = &8u16 — присваивать указатели или ссылки разных типов (ссылка в указатель того же типа — разрешено, обратно — запрещено, т.к. ссылка, в отличие от указателя, не может быть нулевой)
Тем не менее, можно писать 1 as _ + 0.1 as _ — тогда компилятор преобразует типы в какой-то общий, но только при условии, что подходит только один тип, иначе ошибка автовыведения.
Получаешь на вход данные с третьей стороны (из файла или по api) в виде строки (xml, json, yaml) - как вообще можно работать с этими данными без возможности на ходу собрать структуру (массив, объект) с нужным набором полей, их типов и значений?
Ну, типа, теоретически ты пишешь модель или интерфейс, а потом привязываешь данные к ней.
Забавно, но на JS тоже есть библиотеки, поддерживающие привязку объектов к моделям - там класс-модель дополняется декораторами.
Забавно, но на JS тоже есть библиотеки, поддерживающие привязку объектов к моделям - там класс-модель дополняется декораторами.
"данные с третьей стороны" - структура данных изначально может быть неизвестна, либо известна но не полностью.
Разве не для этого проверки и существуют?
Что бы что то проверить, надо что то загнать в память, а что загонять на этапе компиляции/написаниякода/простановкитипов неизвестно.
Вот только не нужно начинать. В твоём случае мы получаем строку. А я говорю о случаях, когда мы НЕ используем данные из вне.
В смысле "как"? Они приходят в виде строки (твои слова), со строкой и работаешь. Вспомни школьные задачи типа получить из строки "12345" число 12345 не прибегая к встроенным функциям конвертации.
Это конечно теоретический вариант, не предлагаю использовать серьезно на практике.
Это конечно теоретический вариант, не предлагаю использовать серьезно на практике.
Эта строка представляет собой не просто числовое или строковое значение, но объект любого уровня сложности и вложенности.
Пример JSON:
{
"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]
}
Это объект типа ключ-значение, в котором ключу "employees" соответствует значение типа массив из объектов, которые в свою очередь содержат пары ключ-значение с для ключей "firstName" и "lastName"
Пример JSON:
{
"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]
}
Это объект типа ключ-значение, в котором ключу "employees" соответствует значение типа массив из объектов, которые в свою очередь содержат пары ключ-значение с для ключей "firstName" и "lastName"
Все еще не понимаю в чем проблема. Когда ты используешь динамическую типизацию разве программа не парсит такую строку, отталкиваясь от скобок, создает дерево или другую структуру на основе этого, с чем и работает? Вот то же самое только ручками.
И у тебя получится написанная своими руками динамическая типизация. Вопрос - нахера?
"виде строки (xml, json, yaml)" - я уточнил что строка не просто одно значение, а структура с множеством значений. Но в целом посыл понятен - работать со "строкой" как со строкой. Но это мало того что не удобно из за примитивности, бывают ситуации когда это попросту невозможно.
тут основная проблема в нелогичном преобразовании типов, что является явным проебом логики языка. А динамическую типизацию можно использовать в различных условных операциях, и для извлечения разной информации из одной переменной для других. Но, при этом, просто брать одну переменную и постоянно менять ее значение разными типами, будто это какай-то общественный сортир, - это признак худшего говнокода, который только можно придумать.
Давайте запилим на вашем типизированном языке какой-нибудь quicksort для интов. А потом quicksort для даблов. Тут мы приходим к шаблонам. И чем больше мы с ними работает тем больше понимаем что нахер их и нахер типы. Если что-то плавает как утка и крякает как утка то это можно считать за утку.
На самом деле большинство довольно привычно, кроме того не надо импортировать непонятные библиотеки и показывать ошибки в них
А что тут странного?
Знак == в операциях с плавающей запятой использовать нельзя в абсолютном большинстве языков, включая все языки низкого уровня.
"===" - это строгое сравнение с требованием совпадения типа, как раз для тех, у кого подгорало от конвертации чисел в строки и наоборот.
Конкретно приведенный тут случая даже описан на W3Schools:
When using the === operator, equal booleans are not equal, because the === operator expects equality in both type and value.
boolean представлен просто как числа 1 и 0, как и ээ... да в абсолютном большинстве языков и даже СУБД.
Любая операция со знаком +, проведенная не над числом, вызывает метод toString(), у массива метод .toString() выводит все его элементы через запятую. Два пустых массива, соответственно, дают две пустые строки, которые при сложении дают тоже пустую строку.
Для объекта метод toString возвращает "[object ClassName]" - в примере выше просто "[object Object]"
Любая операция со знаком - подразумевает конвертацию в число.
И всегда, когда идет конвертация, подразумевается, что программист понимает, что он делает и зачем. Если зачем-то ему понадобилось сложить три булевы переменные, то вероятно он ожидает числовой ответ, не?
Знак == в операциях с плавающей запятой использовать нельзя в абсолютном большинстве языков, включая все языки низкого уровня.
"===" - это строгое сравнение с требованием совпадения типа, как раз для тех, у кого подгорало от конвертации чисел в строки и наоборот.
Конкретно приведенный тут случая даже описан на W3Schools:
When using the === operator, equal booleans are not equal, because the === operator expects equality in both type and value.
boolean представлен просто как числа 1 и 0, как и ээ... да в абсолютном большинстве языков и даже СУБД.
Любая операция со знаком +, проведенная не над числом, вызывает метод toString(), у массива метод .toString() выводит все его элементы через запятую. Два пустых массива, соответственно, дают две пустые строки, которые при сложении дают тоже пустую строку.
Для объекта метод toString возвращает "[object ClassName]" - в примере выше просто "[object Object]"
Любая операция со знаком - подразумевает конвертацию в число.
И всегда, когда идет конвертация, подразумевается, что программист понимает, что он делает и зачем. Если зачем-то ему понадобилось сложить три булевы переменные, то вероятно он ожидает числовой ответ, не?
>Знак == в операциях с плавающей запятой использовать нельзя в абсолютном большинстве языков, включая все языки низкого уровня.
только у других ву-языков обычно для этого есть встроенные классы и методы
>Любая операция со знаком +, проведенная не над числом, вызывает метод toString()
а в более правильных языках вываливается types mismatch
>И всегда, когда идет конвертация, подразумевается, что программист понимает, что он делает и зачем.
или же он ожидал, что придёт массив, но кое-что наебнулось и пришёл null или буль
только у других ву-языков обычно для этого есть встроенные классы и методы
>Любая операция со знаком +, проведенная не над числом, вызывает метод toString()
а в более правильных языках вываливается types mismatch
>И всегда, когда идет конвертация, подразумевается, что программист понимает, что он делает и зачем.
или же он ожидал, что придёт массив, но кое-что наебнулось и пришёл null или буль
Это какие "встроенные методы" есть у, скажем, C или Perl-а для сравнения чисел с плавающей запятой?
> а в более правильных языках вываливается types mismatch
К строкам во многих современных языках разрешено прибавлять числа.
А динамическая типизация внутри числовых типов (int, float, double) существует с доисторических времен.
> или же он ожидал, что придёт массив
От операции сложения массива с объектом посредством знака "+"? Я с трудом себе представляю подобное.
> а в более правильных языках вываливается types mismatch
К строкам во многих современных языках разрешено прибавлять числа.
А динамическая типизация внутри числовых типов (int, float, double) существует с доисторических времен.
> или же он ожидал, что придёт массив
От операции сложения массива с объектом посредством знака "+"? Я с трудом себе представляю подобное.
Кстати, о type mismatch и сложении "не тех типов":
Ну с булом так истроически вышло. Это исключение, а не правило.
Нет такого понятия, как "использовать нельзя", если интерпретатор не сообщает об этом ни ошибкой выполнения, ни даже предупреждением. Даже самый лучший программист иногда допускает обычные опечатки, и вылавливать их с настолько похуистичным интерпретатором - это та еще работа.
Ошибки от интерпретатора или компилятора - это несущественная мелочь. Основные проблемы всегда лежат там, где нет никаких предупреждений и нужно просто понимать, как это работает или что может привести к ошибочному результату.
я более того скажу: реально стремные случаи тут не описаны, например та же сортировка
А что не так с сортировкой?
[1, 2, 3, 10].sort()
За годы практики понял три вещи:
# хер пойми какие кейсы (например сложить бесконечность с ложью и поделить на пустоту для получения неопределености) не проблема, ибо на практике такое писать не будешь.
# динамические скрипты сами по себе то еще приключение и без таких подводных камней впервую очередь из-за отсутствия ошибок "на этапе компиляции", а в рантайме валится чаще где-то дальше проблемного места.
# два преведущих пункта не повод переставать стебятся с того факта, какую лютую дичь можно наваять на JS.
За годы практики понял три вещи:
# хер пойми какие кейсы (например сложить бесконечность с ложью и поделить на пустоту для получения неопределености) не проблема, ибо на практике такое писать не будешь.
# динамические скрипты сами по себе то еще приключение и без таких подводных камней впервую очередь из-за отсутствия ошибок "на этапе компиляции", а в рантайме валится чаще где-то дальше проблемного места.
# два преведущих пункта не повод переставать стебятся с того факта, какую лютую дичь можно наваять на JS.
Я все равно не понял, в чем проблема с сортировкой. Если ты про то, что оно отсортирует по алфавиту, так это прямо в документации и написано. И в Перле так же будет.
Везде, где есть динамическая типизация, нужно указывать функцию сортировки.
Ошибки, незаметные на этапе компиляции, хорошо помогает исправить TypeScript.
Везде, где есть динамическая типизация, нужно указывать функцию сортировки.
Ошибки, незаметные на этапе компиляции, хорошо помогает исправить TypeScript.
Ну если так то уже скорее Интерпретация
Брендон не раз говорил, что у него не было адекватного времени спроектировать js - он накидал прототип "за 10 дней и 10 ночей"
Брендон возглавляет комитет по разработке WASM, и судя по динамике разработки - очень хочет искупить свои грехи
Брендон возглавляет комитет по разработке WASM, и судя по динамике разработки - очень хочет искупить свои грехи
WASM стронг. Я достаточно сложные С++ проекты компилил с успехом. Вот WebGPU еще придет вообще все будет зашибись
Я многое могу понять. Приведение типов, все дела.
Но во имя каких богов, Mathf.max() возвращает "минус бесконечность"
Но во имя каких богов, Mathf.max() возвращает "минус бесконечность"
Насколько я знаю, функция работает так: внутри Math.max(a, b, c) появляется переменная max, которое в цикле сравнивается с a, b, c. Но до начала цикла проверок ему надо назначить начальное значение, которое для любых a, b, c должно быть меньше всех. Таким значением является -Infinity, любой переданный аргумент будет больше или равен. А вот если не задать аргументов, то вернется начальное значение. Думаю изначально это можно было назвать багом, но в итоге это было задокументировано и стало фичей, как к примеру typeof null === 'object'.
это не баг, это нормальная функциональность и минималистичность кода. можно было напихать кучу проверок: а что если юзер не задал аргументы? а что если только один аргумент, а что если не-числовые значения... защита от дурака получится слишком громоздкой и тормознутой
Вспомнилась история с файлами в линукс, название которых начинается на точку. Изначально не планировалось, нужно было скрыть папки . и .. А в коде просто добавили проверку на одну точку в начале имени. Как итог - механизм скрытых файлов. "можно было бы назвать багом, но"
прикольно, буду знать :)
думаю, там функция а-ля:
max = (...args) => {
let result = -Infinity
args.forEach(arg => {
if (arg > result) {
result = arg
}
})
return result
}
и минус бесконечность поставили, что бы первая проверка всегда была максимальным числом
max = (...args) => {
let result = -Infinity
args.forEach(arg => {
if (arg > result) {
result = arg
}
})
return result
}
и минус бесконечность поставили, что бы первая проверка всегда была максимальным числом
Скорее даже просто reduce.
А почему 0.1+0.2 не равно 0.3? Должно же быть какое-то рациональное объяснение.
Проблема с представлением чисел в компьютерах. Например, в десятичной системе 1/3 ~= 0,33333... Но в реальном мире мы не можем записать бесконечное количество троек. А число 0.333..333 не полностью равно 1/3. В разных системах исчисления разные числа невозможно записать как десятичную (или скорее n-ичную дробь). Так в двоиной системе, которой пользуются компьютеры невозможно записать 0.1 и 0.2. И это не проблема js
из-за особого формата представления дробных чисел получается 0.30000000000000004
при вычислении дробных значений в большинстве языков получаются приблизительные, а не математически точные значения. для точных значений используются специальные математические библиотеки или с числами работают как со строками, что во много раз медленней, занимает гораздо больше ОЗУ.
при вычислении дробных значений в большинстве языков получаются приблизительные, а не математически точные значения. для точных значений используются специальные математические библиотеки или с числами работают как со строками, что во много раз медленней, занимает гораздо больше ОЗУ.
мдэ блять
Добро пожаловать в реальный мир, Нео.
Там не со второго надо говорить блеать, а с первого. Сравнивать два float-а в нормальных ( C ) языках это false
По-моему на мемасах про джаваскипт всего его уже выучили
Я не понимаю, все эти люди которые не понимают JS, они как думают, что все языки должны быть похожи на те языки которые они уже знают? Это как учить английский и ожидать что там будут те же времена как и в русском. А потом ещё делать мемасы про то какой это странный язык. Ой, лучше буду всегда говорить на русском, он хоть понятный.
Чтобы написать коммент, необходимо залогиниться