Pull to refresh

Comments 175

Странности есть во всех языках, а хейтят за странности только JS и PHP.
Разработчиков в JS+PHP в разы больше, чем в прочих языках, потому и хейтеров также, в разы больше. Плюс, это языки для начинающих, которые делают свои первые шаги и набивают первые шишки. Потом набираются опыта и переходят в другие языки, а первые шишки помнят и ненавидят за них не себя, а языки.
Потому, что это одни из немногих языков, где динамическая типизация ко всему прочему ещё и слабая.
JS и PHP — это языки для начинающих

Вы чего такое говорите? Каких начинающих?
Языки с кучей подводных камней и слабой типизацией намного сложнее, чем те, в которых этого нет. На Java или C# писать код проще, чем на Javascript, а качественный код тем более.
Смысл скриптовых языков другой: на них можно гнать код быстрее. Так как жесткие правила в языках могут быть обузой при качественной архитектуре и покрытии модульными тестами.
Просто у JS и PHP как в анекдоте "в вашем спирте крови не обнаружено", языки (при всем к ним уважении) это одна большая Странность. Так уж сложилось исторически, я помню как девелоперы JS сами угорали от видео про "логику" сравнений и приведений типов в JS.
P.S. Пишу и на JS и на PHP и нисколько не считаю их плохими, просто их создатели изначально не рассчитывали на появление Node.js или что на PHP будут писать фейсбук, а сейчас кое-какие вещи сложно уже исправить из-за обратной совместимости, увы. :(
Я плохо знаю JS, но есть же фантастическая возможность использовать конструкции типа "use strict", позволяющие писать новый код с использованием нового синтаксиса. Почему бы не придумать что-то типа "use super-duper-operators" для исправления ситуации с совершенно непонятными для новичков операторами сравнения/приведения.
Понимаю, наверняка, вопрос задавался не раз, и на него есть разумный ответ. Просто интересно было бы узнать, почему в комитете стандартизации до сих пор придерживаются крыше-сносящих практик.
Все очень просто, представьте вы работаете с Node.js или очень большим фреймворком в PHP, у вас в проекте уже сотни тысяч кода, которые импортируют сотни чужих модулей, которые состоят из миллионов строк кода и после использования "use super-duper-operators" в сотне мест как вашего кода, так и чужого поведение меняется на прямо противоположенное, там где был true стал false и наоборот. Вам придется потратить многие месяцы чтобы исправить все эти ошибки (если вы их вообще исправите).
С другой стороны в экосистеме нет ничего хуже когда половина фреймворков и библиотек работает с одним флажком, вторая половина с другим. По сути единственный способ это придумать новый язык и как-то убедить всех на него перейти. У всех старых языков: Java, C++, Php, JS есть свои проблемы из-за совместимости.
При грамотной реализации число ошибок интеграции со старым кодом будет минимально. Проблемы будут с привычками программистов.
По поводу перейти — у JS думаю нет с этим проблем, синтаксис ES6 все вроде приняли и уже сейчас с babel'ом используют.
Для этого есть eslint. И надо настроить сборщик, чтобы в прод не собирал, если что-то не прошло eslint.
Ну или TypeScript + tslint, как уже подсказали.
В JS по сравнению с другими языками их слишком много, как мне кажется.
JS должен стать языком кросс-компиляции из Java, Kotlin, Python, C# и т.п. Ну или WebAssembly, если взлетит. Тогда про его странности забудут все, кроме создателей кросс-компиляторов :)
JS должен стать языком кросс-компиляции из Java

GWT? Нет уж, не надо.
Вы куда-то назад в прошлое полезли. Сейчас хотят вытеснить JS с этого "поста" тем же WebAssembly, а вы наоборот. Тогда получается и суть WebAsm'а пропадёт.
Так я и говорю, если WebAsm взлетит. Пока-то возможности его практического применения нет?
GWT помер, но, как мне кажется, идея была правильной.
Ну, во-первых, некоторые браузеры его уже ввели у себя. Во-вторых, WebAsm — по сути, язык-посредник. Это его основная роль. Ну, и в-третьих, JS — это скрипт, и, соответственно, передаётся в текстовом виде. WebAsm же бинарный. Т.е. при поднятии виртуальной машины имеем целых 2 плюса по сравнению с JS: снижение трафика и увеличение скорости обработки (всё же последовательность RISC команд проще спарсить, нежели скрипт). Ещё до его внедрения, года 2 назад, читал статейку, что производители аномально им заинтересовались (аномально в том смысле, что натолкнуть производителей на общий стандарт довольно сложно, а тут чуть ли не сами просились). Так что думаю, что не взлететь он может только из-за каких-либо фундаментальных косяков, но скорее всего над чем-то другим думать будут. Всё же JS как основа всего и вся — это костыль.
WebAssembly не будет заменой JS. Собственно, сам webasm — низкоуровневая штука и основная его ниша — написание критичных к скорости частей кода. Наиболее очевидное применение — написание игровых движков. JS со своей инфраструктурой никуда не денется и будет дальше развиваться.
А я и не говорил, что он будет заменой JS. Но для чего нужен JS? По сути, автоматизация веб интерфейса. А для чего используют? Кто во что горазд. У некоторых производителей по поводу WebAsm'а существуют небезосновательные амбиции перевода всего веб на WebAsm. Точнее так: вся инфраструктура останется, но будет робить под WebAsm'ом, в т.ч. и JS (т.е. компиляция JS в WebAsm), что имхо вполне логично и грамотно.
UFO just landed and posted this here
Честно говоря, мне сложно ответить на ваш вопрос, но тезис:
кроме исторически сложившегося и уже окостеневшего

я поддерживаю. Я не особо ориентируюсь в веб, так что мои знания о JS:
отсутствие типизации (что уже довольно странно); куча надстроек (исторически сложилось: в нём производители видели что-то вроде ассемблера для веб, но скриптовость явная помеха этому); по аналогии с VBS: урезанная java (на сколько — увы, не знаю, если на том же уровне, что vbs, то это печально); м.б. ещё что-нибудь знаю, но сразу не вспомню.
Для меня из плюсов: неплохо дружит с батниками :)
На сколько мне известно, пхп тоже довольно устаревший. Вот даже интересно, на чём сейчас современно сайты писать?
UFO just landed and posted this here
Да какой там флейм… Сам я не веб программист, ближе к системному. Но с этим в РФ мягко говоря не очень (пресловутые китайцы). По этому и планирую в веб, скорее всего как раз на JS. Вот и хотел узнать, что ещё существует. У Вас вроде не полный список. Есть ещё что-то у майкрософта, но последние тенденции их IDE мне как-то не очень.
UFO just landed and posted this here
А можно и на С++. Есть Erlang, Clojure, Scheme, Go, Haskel (!)

Да и не только, в этот список можно включить любой язык, работающий со стандартным (консольным) вводом-выводом. Собственно, это всё одним словом и называется CGI (если конечно к кому-нибудь из них не привинтили транслятор в JS). С CGI немного имел дело, правда, так сказать, "по ту сторону баррикад": сервер с нуля поднимал. Время правда тогда не хватило, потом заброшен был. Думаю, ещё вернусь. Тогда это делалось всё на VB6 (Winsock Control+WinAPI), сейчас уже не плохо было бы на C++ + WinAPI.
Кстати, а по БД какую-нибудь литературу можете посоветовать? Что-нибудь их проектирования. Просто есть жуткая проблема: как только сталкиваюсь с БД, код становится отменным набором костылей и велосипедов (либо тонны однотипных запросов, либо тщетные попытки реализовать в ООП), что раздражает.
По поводу IDE, PHPStorm, я так понимаю, заточен под PHP? Мне Brackets советовали. Даже скачал, запустил. Вроде не тормозит, значит хороший.
Ubuntu или Debian

От Ubuntu (а точнее от KUbuntu) нехорошие впечатления остались. Вообще, я любитель аскетичного софта. В этом плане из окон люблю WinXP, а в Linux среде пока выбор стоит между Gentoo и Debian. Кроме того, приглянулась оболочка lxde.
В остальном, спасибо за советы и пояснения.
UFO just landed and posted this here
Спасибо за развёрнутый ответ.
Всё же немного пофлеймлю :)
PHP — я правда не понимаю, почему был выбран именно такой синтаксис: ->, =>, ::. Это и выглядит не очень, и писать неудобно (тире и угловая скобка находятся в противоположных рядах клавиатуры).

Ruby и Perl — побратимы. Первый написан японцем, второй — лингвистом. Мне одному здесь видятся иероглифы и клинопись?
def push(n)
    @args ||= []
    @args << n
end

%h = ("Lennon"=>"John","Lenin"=>"Leonid");
print $h{"Lennon"}, "\n";
$h{"df0"}="DF)";
print %h,"\n";

for(keys %h){
    print "$_","-","$h{$_}\n";
}

for(sort keys %h){
    print "$_","-","$h{$_}\n";
}

$h{"df01"}="DF)!";
print scalar(%h),"\n";
print values %h, "\n";
print %h, "\n";

for($i=0; $i<100;$i++){
    $h{$i}="$i";
}

print scalar%h,"\n";
$h1{1}='1';
$h1{01}="2";

print scalar %h1,"\n";

print $h1{1},"\n";

ES6 — вместо того, чтобы решить вопрос с приведением типов (время как раз подходящее, babel сильно помогает в плавном переходе), они пихают синтаксический сахар и доп. способы объявления переменных… и еще одну реализацию ООП. 8(

Python — проблема 3-й ветки в том, что хотели провести глобальную ревизию, но испугались из-за несовместимости с уже существующим кодом, потому получилось, что ветки почти взаимозаменяемы, вроде даже ВМ не тронули. Непонятно, зачем убрали range ;(

Идеология питона — есть только один верный путь — не понятно откуда там десять вариантов. Я так понимаю вам был нужен этот код (выводит в консоль содержимое ответа по url с 101 символа и до конца):
response = urllib2.urlopen('http://ya.ru')
data = response.read()
print data[100:]
UFO just landed and posted this here
По поводу обфускации на перле — так можно и на Python:

Ну и эпичное: https://liftoff.github.io/pyminifier/#special-sauce

Кроме того, приведенные мной, пример кода на Ruby — из доки cucumber.io, пример кода на Perl — из туториала по использованию хэшей. Оба примера — обычный, не обфусцированный, не оптимизированный код.


для неоптыного — «ну почему так все сложно? я просто хочу скачать страничку!»

https://docs.python.org/2.7/library/urllib2.html#examples

Stackoverflow: топ ответов в обоих вопросах как раз подтверждает мои слова — "есть только один правильный путь".
Да, вы можете использовать сторонние либы, но зачем? Вы всё можете сделать тем же urllib2 или open. И примеры обычно уже есть в доках. А вот со сторонними либами действительно могут быть проблемы...


Ну и ради контраста — итераторы.

На мой взгляд итераторы в Python если не проще, то точно не сложнее.


Я работал с babel только в контексте React'а, а там он (ES6) фактически уже стандарт, вместе с JSX.
Более того, многие ведь пишут на TypeScript…
ES6 уже почти полностью поддерживается Хромом, так что, думаю, вполне реально форсировать изменения в типизации.
UFO just landed and posted this here
UFO just landed and posted this here
По-настоящему WebAsm «полетит», как мне кажется, тогда, когда его не просто поддержат все браузеры, а когда закостенелый энтерпрайз обновится внутри до нужной версии IE (или того, на что они там перейдут).
JS неплохо минифицируется и достаточно шустро уже исполняется. Я не знаю как устроены современные JS-движки в браузерах, но не удивлюсь, если окажется, что внутри они на лету компилируют JS и исполняют его в виде байт-кода или вообще native-кода. Но, я согласен, это всё скорее просто из-за того, что «так заведено», или то самое «исторически сложившееся и уже окостеневшее», и нормальный с нуля разработанный под браузерные нужды байт-код конечно лучше.
Аномальная заинтересованность мне тоже необычна; возможно это связано с тем, что поддерживать JS с его «особенностями» всех уже так достало, что вовремя поднятый флаг привлёк всех :)
Ну, я не говорил, что быстро взлетит. Бывает так, что хорошие технологии ну очень долго взлетают. Вспомнить тот же UEFI, который в базовом варианте существует с середины 90-х, а полноценная спецификация появилась в нулевых. При этом обширное использование началось порядка 6-7 лет назад. И то, сейчас какого-то толкового комьюнити по программированию и использованию UEFI нет, только голые стандарты, да горстка тем на форумах (стоит отметить, под встроенную виртуалку компиляторов, отличных от ассемблера я так и не нашёл). С настройкой ещё помогут, а программирование — тёмный лес. А некоторые даже не слышали о нём.
Большинство узнало об UEFI только в связи с выходом Windows 10.
Хотя первой из окон под UEFI была то ли виста, то ли семёрка. Причём, многие, у кого был UEFI об этом даже не знали. Понимаю у друга навороченный UEFI, там разительное отличие от BIOS, но на большинстве меню настроек идентично.
UFO just landed and posted this here
Да, была, но простые смертные действительно её не видели (а если быть точнее, не видели итаниум), поэтому не учитывал.
Не критикуют только мертвые языки, но с php, пожалуй, соглашусь.
Приведите пример на C#. Нет, я не злорадствую, мне действительно интересно и даже обидно что его тут не упомянули :)
Ну, например:
static void Main(string[] args)
{
SomeEnum thisEnum;
thisEnum = (SomeEnum)50;
Console.WriteLine(thisEnum); //50
}

public enum SomeEnum
{
One,
Two,
Three
}
Нет, понятно что enum это «integral type» и по дефолту «int». Но все же…
В живую на это можно напороться принимая от девайса какие-то значения\состояния и дальше рассматривая их как enum. Например:
public enum DeviceState
{
On,
Off
}
А тут раз и девайс выдал недокументированное «Intermediate» состояние = 2. А дальше у вас switch или что-то такое. Утрированный пример, но разок такое было.
При переходе с python на ruby, истинный ноль сначала ошарашивает, а потом понимаешь на сколько это красиво.
В Go тоже присутствует автоматическая вставка точки с запятой и авторы советуют пропускать их там, где они не требуются явно. По началу не приятно, но на практике это правило приводит к красиво отформатированному тексту (плюс питона), без жестких требований (длинющие однострочники через; допустимы).
При переходе с python на ruby, истинный ноль сначала ошарашивает, а потом понимаешь на сколько это красиво.
Можно подробнее???
К примеру у вас есть выражение, отвечающее на вопрос "по какому индексу?". Ответ 0 покажет, что элемент присутствует и находится по 0 индексу, а значит должен расцениваться как true. К примеру:
input = "test"
puts "Match!" if /test/ =~ input
puts "At: #{/test/ =~ input}"
# Match!
# At: 0

Часто в выражениях "значение или значение по умолчанию" такие значения, как 0, "", пустые коллекции все же являются true значениями, а потому не должны заменяться значением по умолчанию:
[0, 1, nil].each do |val|
  puts val || "(none)"
  # 0
  # 1
  # (none)
end

Во всяких однострочниках с boolean callbacks, где сторятся промежуточные выборки, не требуется писать (value || value == "") если фильтруем по строкам. Еще более это полезно, при работе базой данных, так что логика работы NULL, 0 и пустых строк отчасти совпадает. С другой стороны, в рельсах часто используется value.present?, чтобы добиться значения false от пустых строк, пустых коллекций и т.д. В целом, дело вкуса.
Для меня как-то очень странно, что после работы с питоном для вас булевое приведение при поиске индекса подстроки в руби выглядит красивее, чем питоновский 'sub in string'
Хех. Сразу вспомнился request.xhr? из rails возвращающий либо nil либо 0.
про руби ниже написал ) Но тут тоже классные примеры приведены. Я к тому же вел — поведение конкретное изменить ничто не мешает, вопрос вкуса. А "голое" — очень понятно.
при переходе с php на ruby навсегда забываешь про конструкции типа if (strpos(...) === FALSE)
Описание кейса в статье отвратительно неграмотное. Во-первых, в Руби нет ключевого слова или типа TRUE, это просто название константы, которая содержит значение true, и никто в сообществе саму константу не использует, ну да ладно, это привет сишникам с макросами из 90х. В языке нет неявного приведения типов с потерей данных, как в js и некоторых других плохо спроектированных языках. Т.е. в языке и true == 0 и false == 0 будет всегда однозначно false, потому что 0 и true/false — это разные типы. Вторая часть утверждения "только boolean false и нулевое значение (nil) вычисляются в FALSE" — полный бред с точки зрения языка.
В чем же дело на самом деле.
Дело в "хитром" устройстве операторов if, case и тернарного оператора, которые трактуют все значения, кроме nil и false, как true. В том числе это: 0, отрицательные числа, комплексные числа, пустые строки и полные массивы, объекты любых других классов и т.д. Ничего по факту не вычисляется, грубо говоря это проверка для "значение nil или false — значит выражение ложно, иначе — истинно". В языке верны только выражения true == true и false == false, все эти домыслы про 0 == true от незнания поведения такой простейшей конструкции языка, как условный оператор.
На мой взгляд это логичное поведение оператора if и оно намного лучше, чем Сишное, где отдельных булевских типов не было, и пришлось заменять false нулем и потом таскать везде макросы #define FALSE 0. Зачем это поведение тащили в js — для меня загадка. К слову, Java и C# этот атавизм (0 == TRUE) не поддерживают и даже не скомпилируют код с ошибкой, что, на мой взгляд, является самым правильным решением проблемы в принципе.
В lua, кстати, то же самое с истинностью. Это иногда удобно, а иногда удобнее вариант Python: здесь в стандартных типах ложно всё, что 0 или пусто, а в своих вы можете сами задать критерии. Конечно, приведение типа к bool вызовом метода сильно хуже с точки зрения производительности, но писать not obj вместо, к примеру, проверок на равенство длины нулю довольно удобно, если вы знаете тип obj.
Требование использовать только и исключительно булевые значения в условии if является самым правильным решением, если вы пишете язык со строгой типизацией. Python и Ruby имеют варианты, соответствующие замыслу их авторов.
#irb
2.2.1 :004 > true
 => true
2.2.1 :005 > true.class
 => TrueClass
2.2.1 :006 > true.class.class
 => Class

так что тип (класс) TrueClass в руби есть
Прочитайте мое сообщение более внимательно, я говорил про TRUE, а не про true.
2.2.3 :001 > TRUE
 => true 
2.2.3 :002 > TRUE = false
(irb):2: warning: already initialized constant TRUE
 => false 
2.2.3 :003 > TRUE
 => false 
При мемоизации, может быть функция/вычисление, чей результать любое целое число, вычисление тяжелое, но вычислить достаточно лишь раз при первом обращении. Если бы 0 == false, то необходимо завести дополнительный флаг, который бы показывал, что вычисление уже выполнено, а в случае Ruby имеем такие конструкции:
def foo
  @bar ||= begin
    #вычисляем значение
  end
end

Если результат может принимать значения true или false
def foo
  return @bar unless @bar.nil?
  @bar =  #вычисляем значение
end

Если результат может быть и nil в том числе
def foo
  return @bar if defined? @bar
  @bar =  #вычисляем значение
end
В отличии от JS, в GO такое не сработает:
func a() int {
return
3
}

Но в JS это полностью валидный код. Типизация помогает избавляться от таких ошибок.
В Go многое не сработает, к примеру:
// скобки не обязательны
// сразу после ) компилятор поставит ';' и ругнется: missing condition in if statement
if (variable > 0)
{
  fmt.Printf(variable)
}

Я видел многих людей и много guideline'ов для C-подобных языков, советующих переносить фигурную скобку на следующую строку для лучшей наглядности. Совет имеет смысл, но в Go нереализуем. Go вообще подходит с позиции мягкой силы. Красивое оформление кода награждается отсутствием ';'. Но если что, с компилятором идет gofmt, который превратит любую кашу в легко читаемый код. Обычно gofmt ставится на хуки в git, чтобы в репозитории все добровольно-принудительно придерживались одного стиля.
Иногда приходится править исходники на других языках, добавляю строки без отступов, сохраняю и сразу возникает недоумение, почему они не стали на свое место? На столько привыкаешь к gofmt при сохранении файла.
Тут вы не совсем правы, го не ставит; и потом ругается, го требует скобочку на той же строке, ибо это символизирует конец условия. Тут не в; дело, фигурные скобки — это отдельная независимая проверка.
Присоединяюсь к просьбе подробностей как истинный ноль (равно ложный ноль) может быть красивым. Мне кажется в языках подобных Ruby и Python, где есть полноценный булевский тип, вообще не стоит опираться на числовое значение как на булевское, как это принято в C, где полноценного булевского типа нет.
UFO just landed and posted this here
Город-побратим Нью Йорка? =)
UFO just landed and posted this here
UFO just landed and posted this here
Не во всяком ться есть лишний мягкий знак. Более того, правило применения тся/ться великолепно ложится именно на устную речь: http://tsya.ru/mnemonic.html
UFO just landed and posted this here
Ну, не знаю, меня ещё в школе учили правилу "делает — делать"...
UFO just landed and posted this here
Есть эпичней :)
isNaN(NaN) // true
isNaN(undefined) // true
isNaN({}) // true
isNaN(new Date().toString()) // true
isNaN(«words») // true
UFO just landed and posted this here
В Lua больше всего удивило, что индексы массивов начинаются с единицы и объекты присваиваются по ссылке, а не по значению.
a = {x = 1}
b = a
a.x = 2
print(a.x, b.x)
>2 2
В Lua можно привыкнуть к тому, что индексы начинаются с 1, а вот отсутствие «continue» раздражает.
Да черт бы с ним с continue, в Lua для побитовых операций надо библиотеку импортировать и функции оттуда вызывать!
Как вам нравится bit32.band(a,b) вместо a&b?
UFO just landed and posted this here
Обновитесь до Lua 5.3. Будет a&b.
Обьекты почти везде по ссылке присваиваются а не по значению.
Я, если не ошибаюсь, то в Lua массивы — это таблицы. И у них может быть не только нулевой, но и отрицательный индекс.
А по умолчанию массивы начинаются с 1 из-за того, что вроде как, так сложилось исторически — Lua разрабатывалась для нефтяной промышленности, а там чуваки не секут в программировании — им привычней с 1.
Скрытый текст
Lua is descended from Sol, a language designed for petroleum engineers with no formal training in computer programming. People not trained in computing think it is damned weird to start counting at zero. By adopting 1-based array and string indexing, the Lua designers avoided confounding the expectations of their first clients and sponsors.

Anyway, there are a couple conveniences to using 1-based indexing. Namely, the # (length) operator: t[#t] access the last (numeric) index of the table, and t[#t+1] accesses 1 past the last index. To someone who hasn't already been exposed to 0-based indexing, #t+1 would be more intuitive to move past the end of a list. There's also Lua's for i = 1,#t construct, which I believe falls under the same category as the previous point that «1 to the length» can be more sensible than indexing «0 to the length minus 1».

Possible justification: C only did it because an array is basically just a pointer and array[0] == array + 0;, and 1-based counting is more natural when array is really a hash table.

(http://stackoverflow.com/questions/2785704/why-do-lua-arraystables-start-at-1-instead-of-0)
Отрицательный индекс (в отличном от «считать с конца массива» смысле) и в C есть: просто передавайте не начало массива, а середину, никто не запрещает. Но так весьма редко делают по той же причине, что и в lua: стандартные функции (та же free) рассчитывают на соблюдение определённых соглашений, Если та же #table для таблиц с нулевым первым индексом в lua всего лишь выдаст индекс последнего элемента (вместо длины) или 0 (для пустой таблицы, т.е. 0 будет для как для таблицы с одним, так и с нулём элементов), то table.concat просто проигнорирует первый элемент.
Luajit #table ещё и странно оптимизирует: к примеру, в lua #{[0]=1, [2]=2} — это 0, в luajit это 2. Но это не «посмотри количество заполненных ячеек в хэше и проверь, есть ли элемент с таким номером»: #{[0]=1, [10]=3, [3]=2} даёт 0, #{[0]=1, [1]=3, [3]=2} даёт 1, a #{[0]=1, [2]=3, [3]=2} даёт 3, тогда как в lua только вариант с «0, 1, 3» даёт тот же результат, а остальные нули.
UFO just landed and posted this here
Некоторые вещи с произвольными индексами не дружат. Например, как узнать размер массива:
print(table.getn{[0] = 1, 2, 3})
> 2
UFO just landed and posted this here
по уму ИНДЕКСЫ и должны начинаться с единицы, с нуля начинается СМЕЩЕНИЕ

индексы с нуля упрощали перенос алгоритмов придуманных для линейного размещения данных в памяти
Индексы — это просто ключи доступа к элементам, они могут быть чем угодно и начинаться с чего угодно, и даже могут иметь разрывы в последовательности или вообще не быть последовательными. Индексами могут быть строки, например (ассоциативные массивы). Или ряд натуральных чисел. Или смещения в памяти. Выбор диктуется областью применения. Низкоуровневые массивы вполне естественно индексировать смещениями, для прикладных (математических) массивов естественнее натуральный ряд (Фортран, VB, Lua etc).
С единицы начинается номер элемента массива. А индексы массивы вообще говоря просто какое-то абстрактное множество. Целые положительные или целые неотрицательные числа — частные случаи.
Индекс всё-таки больше с номером ассоциируется — чаще имеет прикладное значение. А отсчёт с нуля — отсылка к (неактуальной) реализации. Мне кажется высокоуровневые абстракции должны быть ближе к естественному положению вещей. То, что в некоторых языках пытаются заново переосмыслить сущности, а не следуют догмам — хорошая практика.
В LabVIEW разным терминалам и индикаторам можно смело давать одинаковые имена (имена, кстати, можно вообще давать любые — набор символов ничем не ограничен).
Это как если бы мы написали что-то такое:
int x = 1;
int x = 2;
int y;
int y;

y = x + 3;
y = x + 4;

Одного взгляда вот на такой код будет недостаточно, чтобы сказать, каков будет результат:
image
Равно как и нельзя сказать, какой результат будет вот в таком случае, так как порядок исполнения операторов не определён:

Всё это валидные конструкции. Их можно отловить статическим анализатором, но некоторых новичков это дело вводит в ступор.
Oracle считает строки нулевой длины эквивалентными NULL

Мне лично — это удобно и привычно.
в Oracle предупреждают, что в ближайшем будущем подобное явление пустой строки может исчезнуть

Ох и много legacy-кода в этом случае полетит с неожиданными ошибками-сюрпризами! Потому что, не я один исхожу из того, что строки нулевой длины эквивалентны NULL — я такое постоянно встречаю в унаследованном коде.
Я вангую, что просто сделают опцию в базе данных, как рассматривать пустую строку, чтобы старый код не падал.
Возможно, сделают тип VARCHAR с поведением, как по стандарту; и оставят тип VARCHAR2 таким же, как сейчас.
в оракле не разбираюсь, но уверен естественно есть опция "не может быть NULL" или некие еще надстройки какие неоднозначность убирают.
Плюс валидация на уровне приложения. Не думаю что у ораклистов это "проблема" )
Python:
a = ([1,2,3], )
a[0].append(4)
print a
a[0] += [5]
// exception
print a
def a(somevar=[]):
somevar.append(1)
return somevar

print a() # -> [1]
print a() # -> [1, 1]
print a() # -> [1, 1, 1]
print a() # -> [1, 1, 1, 1]
От такого иногда плачешь немного недоумеваешь.
Ну об этом в доках сразу предупреждают. Значения для аргументов по-умолчанию вычисляются только один раз, когда считывается файл модуля с этой функцией. Если значение mutable, получается что-то похожее на замыкание.
Сам факт описан в доке, но не ясно каких целей придерживались авторы языка. К примеру в ruby/rails быстро привыкаешь писать:
def some_text_snippet(locale=I18n.locale)
  # здесь locale = I18n.locale  будет вычислятся при каждом вызове
  # в I18n.locale лежит язык пользователя, устанавливаемый из профиля, URL, Accept-Language и т.д.
end
Я предполагаю, что тут речь идёт о том, что списки в питоне мутабильны, и аргумент в функции уже ссылается на существующий объект, так как функция компилится в момент объявления. Вроде так.
def a(somevar="asd"):
    somevar = somevar + "v"
    return somevar

print a()    # asdv
print a()    # asdv

print a("dfdsf")    # dfdsfv
print a("dfdsf")    # dfdsfv

def b(somevar=['a','b']):
    somevar.append('v')
    return somevar

print b()    # ['a', 'b', 'v']
print b()    # ['a', 'b', 'v','v']

print b([1,2,3])    # [1, 2, 3, 'v']
print b([1,2,3])    # [1, 2, 3, 'v']

x = ['o','p','q']
print b(x)    # ['o', 'p', 'q', 'v']
print b(x)    # ['o', 'p', 'q', 'v', 'v']
Функция с таким же успехом могла компилироваться не в «код + значения по‐умолчанию» а в «код + код получения значений по‐умолчанию», как в Ruby, по словам предыдущего комментатора. Изменяемые списки тут не при чём, если они будут создаваться каждый раз при вызове, то таких побочных эффектов не будет.
Но если взять за пример представленную выше функцию, то её аналог в руби будет вести себя по-разному в зависимости от того, передали ли мы в функцию аргумент, или нет:
def a(somevar=['q','w','e'])
    somevar.push('v')
    return somevar
end

a()    # ["q", "w", "e", "v"]
a()    # ["q", "w", "e", "v"]

x = [1,2,3]
a(x)    # [1, 2, 3, "v"]
a(x)    # [1, 2, 3, "v", "v"]

В общем, и в руби, и в питоне эти механизмы не являются интуитивно понятными, ИМХО.
Питоний стиль скорее "от вызова", а стиль руби — "от кода".
А вообще стоит всегда стараться использовать чистые функции :)
В общем, и в руби, и в питоне эти механизмы не являются интуитивно понятными, ИМХО.

ИМХО как раз в питоне не совсем очевидно, т.к. в тех языках что видел, значение по-умолчанию всегда подставляется новое, а не берется ранее вычисленное.
Это как раз логично, append добавляет элемент к списку, модифицируя его in-place. a[0] += [5] эквивалентно a[0] = a[0] + [5], что создаст новый список и попробует записать его по нулевому индексу в tuple — но tuple неизменяем, и это невозможно, о чём exception любезно скажет. Если очень хочется, можно делать так: a[0].extend([4])
Магия тут в том, что после того как python выбросит Exception с ошибкой "Я не могу подифицировать tuple", мы можешь распечатать этот самый tuple и увидить что в массив внутри него все же был добавлен элемент.
Никакой магии. Просто код
a[0] += [5]
заменяется на что-то подобное
b = a[0].extend([5]) # расширяет list "in place"
a[0] = b # при присваивании выдается исключение
a[0] += [5] эквивалентно a[0] = a[0] + [5]

Нет, не эквивалентно.
x + y — берет аргумент x и y, получает сумму и ее возвращает.
x+=y — берет аргумент x и по месту его модифицирует, после этого возвращает его.
Поэтому во втором случае и получаем побочный эффект — исключение выдано, а список все равно изменился.
import operator
a = [1]
b = [2]

c = operator.add(a, b)
c is a # False

c = operator.iadd(a, b)
c is a # True
Можете привести кейсы, где пустая строка обязательно должна быть не NULL?
Я работал с Ораклом, и там пустая строка есть NULL ("" IS NULL), и это никак не мешало. Мне кажется это даже удобно.
Строковой номер элемента:
1) пустая строка: кому-то лень было вводить артикул, но поля заполнили
2)Null: нет такого элемента
"Префикс" + Null = нет такого элемента, а не элемент "Префикс"
В конце концов Null превратить в пустую строку вобще не проблема, а понять где Null если уже всё слепили в один ком… это зло в чистом виде.
Если в хранимой процедуре есть параметр типа varchar2, то вы никогда не узнаете, был он пустой намеренно или его просто не передали. Т.е. сделать апдейт в значения таблице на пустой или ничего не делать если он налл.
Т.е. сделать апдейт в значения таблице на пустой или ничего не делать если он налл.

какая разница делать ли апдейт или нет. Ведь null — это и есть пустая строка в Оракле. Что сделал апдейт, что нет — одинаково. Вывод — апдейт можно не делать
Если в строке было значение и надо понять, скинуть его в пустое или не менять вообще, то определить это можно только лишними костылями.
В результате для того чтобы отличать в оракле пустую строку от null вводится маркер, обозначающий пустую строку, обычно это единичный пробел — он отобразится в любом софте без обработки null. А потом, когда вы начинаете поддерживать что-то кроме оракла, вы не можете отказаться от этого маркера, т.к. нужна совместимость по sql, репликации и проч.
Ну, например условие джойна. Вот там пустая строка и null будут очень сильно влять на логику
добавить в условие JOIN:
OR (t.str is null and t2.str is null)
JavaScript: В Java тоже конкатенации строк + и она даже умеет складывать так числа и строки вместе в новую строку.
PHP: Не чувствительность регистра есть в Pascal и Delphi, но больше всего странно то, что в php она только для методов, классов и функций.
Ruby: Все таки думаю в ruby просто любой объект считают true, а 0 это объект в ruby, поэтому есть в этом своя логика.
Да, но в Java статические типы как аргументов, так и результата и ошибку с использованием + сделать значительно сложнее (вот деление double на int реально выносит мозг когда про него забываешь/не заметишь). На самом деле, оператор + и — в JS работает куда веселее когда в одном из аргументов оказывается массив, объект, null, undefined и т.п. Пересказать не смогу, лучше посмотреть видео тут (про JS начинают говорить с 1:20). Ну или почитать эту статью.
думаю в ruby просто любой объект считают true

false и nil – тоже объекты
Чувствительность к регистрам PHP
+ как универсальный оператор конкатенации в JavaScript
Автоматическая вставка точки с запятой в JavaScript

Такие проблемы встречаются только в теории, а на практике никто в здравом уме не будет сложит 1 + '1' или назвать 2 метода с разным регистром.
а на практике никто в здравом уме не будет сложит 1 + '1'

Ты можешь сложить две переменных, в обоих хранится число, но случится конкатенация, так как тип одной переменной строка.
var text = "asd_234";
var match = text.match(/_(\d+)$/);
var a = match[1];
var b = a + 3;//ожидаем 237, получим '2343'
В то время как большинство языков программирования чувствительны к регистру, в PHP названия функций, классов и методов к нему нечувствительны.
Доподлинно неизвестно, откуда повелось такое расхождение, но наиболее вероятный вариант — изначальное желание создателей PHP выделить интерфейс CGI в отдельный полноценный язык программирования.

Да все очень просто — очень часто название класса, функции или метода берется из URL и это сделано для того, чтобы однозначно, быстро и просто сопоставить некий URL вроде
http://mydomain/verygoodcontroller/thebestmethod?params
независимо от регистра — вызову конкретного метода в конкретном классе:
class VeryGoodController
{
    public function theBestMethod()
    {
         ....
   }
}
Что-то сомневаюсь, что роутинг и контроллеры повсеместно использовались во времена PHP 1. :)
Это плохо вяжется с class loading'ом по названию класса в PHP и регистрозависимостью имен в файловой системе Linux, например.
UFO just landed and posted this here
Это и есть перевод этой статьи
Скорее статья написана по мотивам опроса со stackoverflow.
Нет, в статье упоминается некто Artem Russakovskii, который есть на stackoverflow. Так что на stackoverflow раньше появилось.
никогда раньше на слышал и не встречал, чтобы в Си (и Си++) писали 4[arr]. специально сейчас проверил, думал на тип ругнется. не, сожрал.
меня еще в Си удивляет, что имя в объявлении структуры — это не тип.
UFO just landed and posted this here
Имеется в виду то, что в C есть пространство тегов структур/объединений/перечислений, отдельное от пространства имён типов. Т.е. в объявлении «struct T {… }» имя структуры (тег) «T» не является именем типа, ибо настоящим именем типа является «struct T». Отсюда извраты с повсеместным «typedef struct T {… } T»

В С++ это не так — тег класса (и, по аналогии, структуры/объединения/перечисления) автоматически объявляет новый тип, и можно запросто писать «T *t;» вместо «struct T *t;»
UFO just landed and posted this here
Оракловый NULL может показаться ужасным при хранении данных, но с точки зрения преобразования данных мы получаем некоторый плюс: конкатенация с NULL по факту работает как конкатенация с пустой строкой, а не обnullяет весь результат. Конечно обнуление строки при конкатенации с null тоже может использоваться в логике преобразований, но на моём опыте первое поведение требуется значительно чаще второго.
Да и стоит отметить, что код без кучи вызовов COALESCE/NVL выглядит чище и легче читается.
В JS ‘1’+1=2, а не '11', а вот 1+'1' = '11'. Приведение типов в операторе "+" идет по правому операнду.
Нет, результат будет одинаковым. И там и там будет '11'
Зато вот так прикольней :)
> undefined
undefined

> {}
undefined

> {}+1    // {} -- null?
1

> undefined+1
NaN

> {}+'1'    // {} -- wtf?
1

> undefined+'1'
"undefined1"

> {}+null    // {} -- null?
0

> undefined+null
NaN

Пример несколько наигран — такой код вряд ли встретится в реальности ({} — здесь пустой блок кода), однако забавно.
{} — это не только пустой блок кода, но и пустой объект
Когда стоит в начале строки — это блок кода.
> x = {}+[]
"[object Object]"

> {}+[]
0

> +[]
0

> x = { a:10, b:20 }
Object { a: 10, b: 20 }

> { a:10, b:20 }
SyntaxError: missing ; before statement

> a:100
100

> { a:100 }
100
А что тут неожиданного?
Ruby
a = 'a' && 'b' => 'b'
b = 'a' || 'c' => 'a'
"И" требует истинности всех аргументов и вернется результат последнего вычисленного
После C/C++, Java, C# и т.п. ожидаешь получить результат булевого типа: True или False, а не значение последнего вычисленного.
Там скорее всего это связано с тем, что языки со статической типизацией и сравнивая теплое с мягким получить мокрое, в них будет разрыв шаблона.
UFO just landed and posted this here
UFO just landed and posted this here
Просто один аргумент можно невозбранно выкинуть. Причём не только второй, но и третий.
UFO just landed and posted this here
Каждый раз заходя в Python я вижу более менее одинаковый код, чего нет в остальных языках.
Именно поэтому идея с отступами гениальна!
Идея хороша, но не всегда удобно. Скопируешь себе кусок интересного кода и вместо того что бы начать с ним [s]играться[/s] работать начинаешь выполнять квест: выделил фрагмент ->Ctrl+[ или Ctrl+]… И так пока не заработает.
Тут есть плюс в том, что вместо бездумного копипаста приходится хоть немного в код смотреть в процессе выравнивания :)
Ха, Оракловские NULL строки им видите ли не нравятся. А то что в Яве (и где еще? шарп, не? не в курсе) все сравнения с нормальных == и ли != превратились в сущий пипец .equalsTo() — про это никто не вспомнил. А код стал похож на овно.
А какое из множества равенств (т.е. отношений эквивалентности) вы считаете более «нормальным»:
1) идентичность: a == b истинно лишь когда a и b — один и тот же объект
2) бинарное равенство: a == b истинно лишь когда содержимое a и b одинаково вплоть до каждого бита
3) посимвольное равенство: a == b истинно, если содержат одинаковые символы текста, даже если у них разная кодировка
4) смысловое равенство: a == b истинно, если содержат текст с одинаковым смыслом, даже если отличаются кодировка, регистр, некоторые символы заменены эквивалентами (например, немецкое двойное с) и т.п.
UFO just landed and posted this here
в Perl модулях необходимость возвращать true связанна с этапом компиляции, на котором выполняется код модуля и есть возможность вернуть false если что то пошло не так. смешные цитаты про бесполезность и раздражение ))
В рубях, на самом деле, здравый подход. false это nil (аналог null пустого значения с оговорками) или сам false. Все остальное true. То есть, с одной стороны если вы кодируете такие методы и исключения какие возвращают nil, беспокоиться не о чем. Единый подход.
Но даже если Ваш метод что-то другое возвращает, проверок различных можно сделать массу.
Это удобно, ребят )))) Избавляет от размышлений является ли false пустая строка (в руби — конечно нет!). И стимулирует использовать родные методы например к строке это .zero?
В Ruby 0 == TRUE

это не так:
#irb
2.2.1 :001 > 0 == true
 => false

ну и для полноты картины:
2.2.1 :002 > 0 == false
 => false
имелась автором в виду не проверка на равенство а вывод в логических выражениях видимо:
puts "это правда" if 0 # число 0 не рассмотрено как false, будет выведен текст "это правда"

то есть все что не nil и не false рассматривается как true в логических выражениях:
puts "Сработало" unless nil #это работает, противоположность nil - true в логическом эквиваленте
puts "Сработало" unless false #это тоже работает
puts "Сработало" if 0 #тоже сработает, 0 - не false
но безусловно я с Вами согласен если заявление звучит как 0 == true это не правда. Как Вы и показали в irb. Эти величины проверку на сравнение не пройдут. Только логическую. Поставил Вам плюс )
А до этого отключили по умолчанию во всех компиляторах, вроде.
Еще в MySql CONCAT('colum1','column2') вернет null если в column2 будет null. Неудобно, когда надо соединить firstname, middlename и lastname, ведь middlename есть не у всех.
Это для всех SQL справедливо, кроме Oracle.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
К особенностям Oracle можно отнести механизм sequence, довольно отличительная черта от остальных RDBMS строящие таблицы с автоинкрементном. А вот строки нулевой длины эквивалентны NULL удобно. Не хотелось бы, чтоб это правило в дальнейшем поменялось.
UFO just landed and posted this here
Остальные — это MySQL? Postgre знает sequence (по сути только его и знает), MS знает.
В MS SQL сравнительно недавно появился sequence. На практике пока встречаю, что многие еще не используют данный механизм
Конечно же от этого больше плюсов — сквозные "айдишки", кэширование, шаг инкримента, начальная/конечная позиция. Но реакция пользователей других СУБД примерно такая же как и когда узнают про is null, вместо = ''
В Perl есть два разных набора операторов сравнения — один для строк, другой для чисел: http://ru.perlmaven.com/sravnenie-skalarov-v-perl


Нужно следить за кавычками в print:
@i = ('a', 'b', 'c');
print "@i";    # a b c
print @i;      # abc

Списковый оператор print. Для запятых слева от него он имеет наименьший приоритет, но повышает приоритет правой запятой.
@i = ('a', 'b', print 'c', 'd');
print "\n",@i;
# cd
# ab1
Sign up to leave a comment.