Страницы

Поиск по вопросам

воскресенье, 30 сентября 2018 г.

Работа с контролами из фонового потока

Ситуация следующая:
имеется окно с кнопкой button1 и меткой label1 по кнопке запускается какая-то долгая операция, в отдельном потоке. по завершению операции нужно вывести результат label1
При попытке поменять значение label1.Text код падает с исключением InvalidOperationException:
WinForms:
Cross-thread operation not valid: Control 'label1' accessed from a thread other than the thread it was created on. Недопустимая операция в нескольких потоках: попытка доступа к элементу управления 'label1' не из того потока, в котором он был создан.
WPF:
The calling thread cannot access this object because a different thread owns it. Вызывающий поток не может получить доступ к данному объекту, так как владельцем этого объекта является другой поток.
Пример кода:
private void button1_Click(object sender, EventArgs e) { (new Thread((s) => { var result = Worker.SomeLongOperation();
// следующая строчка падает c InvalidOperationException: this.label1.Text = result; })).Start(); }
class Worker { public static string SomeLongOperation() { Thread.Sleep(1000); return "результат"; } }


Ответ

Решение для .NET 4.0 и более поздних версий
Использовать Асинхронную модель на основе задач (TAP) и ключевые слова async-await
private async void button1_Click(object sender, EventArgs e) { string result = await Task.Factory.StartNew( () => Worker.SomeLongOperation(), TaskCreationOptions.LongRunning);
this.label1.Text = result; }
Преимущества:
Код значительно короче других вариантов, вызовы записаны в той последовательности, в которой они выполняются. Никаких коллбеков и ручной работы с потоками. async не дает обработчику события завершиться, но при этом не блокирует UI. TaskCreationOptions.LongRunning подсказывает планировщику, что операция будет действительно долгой, и для ее выполнения не стоит использовать пул потоков.
Встроенная поддержка ключевых слова async/await появились в .NET 4.5 и Visual Studio 2013.
Данное решение также может быть использовано для .NET 4.0 и Silverlight 5, если используется версия Visual Studio не ниже 2012. Для этого нужно установить пакет Microsoft.Bcl.Async из NuGet.
Решение с отображением прогресса выполнения
Если в процессе выполнения нужно отображать прогресс или промежуточные результаты из второго потока, то можно использовать класс Progress
private async void button1_Click(object sender, EventArgs e) { var progress = new Progress(s => label1.Text = s);
string result = await Task.Factory.StartNew( () => Worker.SomeLongOperation(progress), TaskCreationOptions.LongRunning);
this.label1.Text = result; }
class Worker { public static string SomeLongOperation(IProgress progress) { // Perform a long running work... for (var i = 0; i < 10; i++) { Task.Delay(500).Wait(); progress.Report(i.ToString()); } return "результат"; } }
Progress захватывает SynchronizationContext в момент создания, и использует его для выполнения операций, избавляя от ручных вызовов Invoke.
Решение для .NET 3.5 и более ранних версий
Использовать Invoke/BeginInvoke
// WinForms: this.label1.BeginInvoke((MethodInvoker)(() => this.label1.Text = result));
// WPF: Dispatcher.BeginInvoke((Action)(() => this.label1.Content = result));
Для .NET 2.0, в котором еще не было лямбд, эквивалентный код записывается с помощью анонимных делегатов:
// WinForms: this.label1.BeginInvoke((MethodInvoker)(delegate { this.label1.Text = result; });
// WPF: Dispatcher.BeginInvoke((Action)(delegate { this.label1.Content = result; });
Полный код:
private void button1_Click(object sender, EventArgs e) { (new Thread((s) => { var result = Worker.SomeLongOperation();
this.label1.BeginInvoke((MethodInvoker)(() => this.label1.Text = result));
})).Start(); }
BeginInvoke поставит код на выполнение в тот поток, в котором был создан label1 и продолжит выполнение фонового потока. При использовании Invoke вместо BeginInvoke фоновый поток будет приостановлен до завершения выполнения кода в UI потоке.

Как работает оператор ==

Как работает оператор проверки на равенство ("=="), имеются ли ему альтернативы и в каких ситуациях следует его применять?


Ответ

Оператор "=="
В Java оператор "==" возвращает значение типа boolean - результат сравнения ссылок на объекты (кроме примитивов), т.е. данный оператор не сравнивает на равенство внутреннее содержимое объектов, а просто проверяет указывают ли ссылки на один и тот-же объект. Таким образом, при сравнении объектов в Java оператор "==" вернет true лишь в том случае, когда ссылки указывают на один и тот-же объект.

Сравнение примитивов
Для примитивных типов (byte, short, int, long, char, float и double) концепция равенства/неравенства достаточно тривиальна: сначала операнды распространяются (т.е. происходит арифметическое распространение (promotion) операндов) до наибольшего если это необходимо, а затем происходит непосредственное побитовое сравнение (если все биты равны, то возвращаемое значение будет true, иначе - false).
Например, значение 48.0f (типа float, соответственно) равно значению '0' (код которого равен 48 согласно таблице символов Unicode) типа char, значение которого неявно распространяется до типа float
Контрольный пример:
char char1 = '0'; int int1 = 48; float float1 = 48.0F; System.out.println(char1 == int1); // true System.out.println(char1 == float1); // true System.out.println(int1 == float1); // true
// ---------------------------------------------
char char2 = 'A'; int int2 = 65; float float2 = 65.0F; System.out.println(char2 == int2); // true System.out.println(char2 == float2); // true System.out.println(int2 == float2); // true

Сравнение вещественных примитивов
Для вещественных примитивов (float и double) существуют некоторые особенности, которые необходимо учитывать. Представление дробной части осуществляется с помощью конечного числового ряда 2^(-n) (где значение числа n зависит от размера мантисы, который в свою очередь зависит от конкретного типа: float - 24 бита – это 2^(-24) ≈ 6*10^(-8), т.е. 6E-8F, либо double - 53 бита – это 2^(-53) ≈ 10^(-16), т.е. 1E-16, что фактически является шагом с которым реально идут значения в представлении данных типов), а потому о точном представлении произвольно взятого числа говорить не приходится.
Само собой разумеется, что две вещественные переменные, проинициализированные одним и тем же вещественным литералом, будут равны (ведь они проинициализировались одной и той же последовательностью бит):
float float1 = 0.7F; float float2 = 0.7F;
System.out.println(float1 == float2); // true
Но стоит начать выполнять арифметические операции с переменными данного типа, как, скорее всего, начнет накапливаться погрешность вычислений (из-за указанных выше особенностей представления экземпляров данного типа):
float float1 = 0.7F; float float2 = 0.3F + 0.4F;
System.out.println(float1 == float2); // false System.out.println(float1); // 0.7 System.out.println(float2); // 0.70000005
Как следует сравнивать вещественные примитивы
Вещественные примитивы (float и double) стоит сравнивать с определенной точностью. Например, округлять их до 6-го знака после запятой (1E-6 для double, либо 1E-6F для float), либо, что предпочтительнее, проверять абсолютное значение разницы между ними.
Контрольный пример:
float float1 = 0.7F; float float2 = 0.3F + 0.4F; final float EPS = 1E-6F;
System.out.println(Math.abs(float1 - float2) < EPS); // true

Использование Pool'ов
Как уже было сказано, оператор "==" проверяет указывают ли ссылки "на один и тот же объект", но иногда под этим простым выражением скрывается нечто большее чем может показаться на первый взгляд.
Для более эффективного использования памяти, в Java используются так называемые пулы: Integer pool, String pool и некотоыре другие. Когда мы создаем объект не используя операцию new, объект помещается в пул, и в последствии, если мы захотим создать такой же объект (опять не используя new), то новый объект создан не будет, а мы просто получим ссылку на наш объект из пула.
Стоит заметить, что использование Integer Pool'а будет осуществляться при любой автоупаковке (autoboxing), если значение соответсвует указанному диапазону, в отличие от строк (String Pool), для которых интернирование (intern) работает для литералов.

Integer pool
Особенность Integer pool'а в том, что он хранит только числа, которые помещаются в тип данных byte: от -128 до 127 (который начиная с Java 7 (раньше это было захардкожено внутри java.lang.Integer) можно расширить с помощью опции JVM: -Djava.lang.Integer.IntegerCache.high=size или -XX:AutoBoxCacheMax=size). Для остальных чисел из Integer'а пул не работает.
Контрольный пример:
Integer valueFromPool1 = 127; Integer valueFromPool2 = 127; Integer valueNotFromPool1 = 128; Integer valueNotFromPool2 = 128;
System.out.println(valueFromPool1 == valueFromPool2); // true System.out.println(valueNotFromPool1 == valueNotFromPool2); // false
System.out.println(127 == valueFromPool1); // true System.out.println(128 == valueNotFromPool1); // true System.out.println((Integer)127 == valueFromPool1); // true System.out.println((Integer)128 == valueNotFromPool1); // false

String pool
Выделим основные ньюансы строкового пула в Java
Строковые литералы (в одном/разных классе(ах) и в одном/разных пакете(ах)) представляют собой ссылки на один и тот же объект. Строки, получающиеся сложением констант, вычисляются во время компиляции и далее смотри пункт первый. Строки, создаваемые во время выполнения НЕ ссылаются на один и тот же объект. Метод intern в любом случае возвращает объект из пула, вне зависимости от того, когда создается строка, на этапе компиляции или выполнения.
В контексте данных пунктов речь шла об "одинаковых" строковых литералах.
Контрольный пример:
String hello = "Hello", hello2 = "Hello"; String hel = "Hel", lo = "lo";
System.out.println("Hello" == "Hello"); // true System.out.println("Hello" == "hello"); // false System.out.println(hello == hello2); // true System.out.println(hello == ("Hel" + "lo")); // true System.out.println(hello == (hel + lo)); // false System.out.println(hello == (hel + lo).intern()); // true
Подробнее про interning можно прочитать здесь

Альтерантивы оператору "=="
Для сравнения двух объектов в Java также существуют такие методы как: equals() и hashCode(). Методы hashCode() и equals() определены в классе Object, который является родительским классом для объектов Java. Поэтому все Java объекты наследуют от этих методов реализацию по умолчанию.
Использование equals() и hashCode()
Метод equals(), как и следует из его названия, используется для простой проверки равенства двух объектов. Реализация этого метода по умолчанию просто проверяет по ссылкам два объекта на предмет их эквивалентности, т.е. просто сравнивает ссылки.
Метод hashCode() обычно используется для получения уникального целого числа, что на самом деле не является правдой, т.к. результат работы данного метода - это целое число примитивного типа int (называемое хеш-кодом), полученное посредством работы хэш-функции входным параметром которой является объект, вызывающий данный метод, но множество возможных хеш-кодов ограничено примитивным типом int, а множество объектов ограничено только нашей фантазией. В итоге, имеем следующее:
если хеш-коды разные, то и объекты гарантированно разные если хеш-коды равны, то входные объекты не всегда равны (это обусловленно тем, что множество объектов мощнее множества хеш-кодод, т.к. множество возможных хеш-кодов ограничено примитивным типом int)
Также про данные методы можно прочитать здесь
Переопределение поведения по умолчанию.
Так как в Java нельзя переопределять операторы (т.е. поведеие оператора "==" не может быть изменено) как, например, в C++ или C#, то для сравнения двух объектов одного класса по необходимому для нас алгоритму, можно переопределить (@Override) методы equals() и hashCode() внутри нашего класса и использовать их.
Таким обарзом, создавая пользовательский класс следует переопределять методы hashCode() и equals(), чтобы они корректно работали и учитывали данные объекта. Кроме того, если оставить реализацию из Object, то, например, при использовании java.util.HashMap возникнут проблемы, поскольку HashMap активно используют hashCode() и equals() в своей работе.

Особенности при работе с вещественными типами Float и Double
В Java NaN'ы несравнимы между собой, но есть два исключения в работе классов Float и Double, рассмотрим на примере класса Float
Если float1 и float2 оба представляют Float.NaN, тогда метод equals возвращает true, в то время как Float.NaN == Float.NaN принимает значение false Если float1 содержит +0.0f в то время как float2 содержит -0.0f, метод equals возвращает false, в то время как 0.0f == -0.0f возвращает true
Контрольный пример 1:
Float float1 = new Float(Float.NaN); Float float2 = new Float(Float.NaN);
System.out.println(float1 == float2); // false System.out.println(float1.equals(float2)); // true System.out.println(Float.NaN == Float.NaN); // false
// --------------------------------------------------
Double double1 = new Double(Double.NaN); Double double2 = new Double(Double.NaN);
System.out.println(double1 == double2); // false System.out.println(double1.equals(double2)); // true System.out.println(Double.NaN == Double.NaN); // false
Контрольный пример 2:
Float float1 = new Float(0.0F); Float float2 = new Float(-0.0F);
System.out.println(float1 == float2); // false System.out.println(float1.equals(float2)); // false System.out.println(0.0F == -0.0F); // true
// --------------------------------------------------
Double double1 = new Double(0.0); Double double2 = new Double(-0.0);
System.out.println(double1 == double2); // false System.out.println(double1.equals(double2)); // false System.out.println(0.0 == -0.0); // true

Подведем итоги
Если вам необходимо проверить не ссылаются ли две переменных на один и тот же объект, либо сравнить на равенство два примитива (но стоит иметь в виду то, что вещественные числа следует сравнить лишь с определенной точностью), то вам определенно стоит воспользоваться оператором "==", но если же вам необходимо сравнить именно внутреннее содержимое объектов (либо для пользовательского типа сравнить по еще какому-то особому алгоритму), на которые ссылаются данные переменные, то вам стоит воспользоваться методом соответствующего класса equals() (причем если это пользовательский класс, то вам стоит переопределить данный метод и при этом не забыть про метод hashCode()).

Регистрация аккаунта разработчика Google Play и вывод денег в России

Мне нужно создать аккаунт разработчика в Google Play для того, чтобы выкладывать свои приложения и получать денежные средства с рекламы в этих приложениях. Какой банковский счёт для этого нужен? Где нужно регистрироваться? Какие есть нюансы при выводе денег в России? Я хотел бы поподробнее узнать про регистрацию аккаунта разработчика в Google Play, про то, какая кредитная карта для этого нужна, и где её получить, и про вывод денег в России.


Ответ

Нужна карта с возможностью платить в Интернете для первоначального взноса в 25 долларов в Google Play (заплатить надо всего один раз, в отличие от яблочного акка разработчика, где платить надо раз в год). Лично я пользовался виртуальной QIWI-картой. Для её получения нужна SIM-карта (для регистрации аккаунта в QIWI). Далее, на сайте или в приложении создаёте карту с любыми данными о владельце и платите. Нужен долларовый счёт с возможностью получать доллары из-за границы. Мне помог в этом Сбербанк (счёт открывают за $5, которые оказываются неснимаемой суммой на счету. Счёт называется "Универсальный"). Дали бумажную книжку по паспорту, реквизиты. Ввёл это в аккаунте - деньги пришли. Далее, если хочется удобств - можно оформить сбербанковскую же карту (за 780 рублей в виде страховки единовременной. Далее можно и не платить её. Нужен паспорт). С ней можно в онлайн-банке доллары в рубли перевести на карту и с карты уже в банкомате наличные снять. Либо по старинке отстоять очередь в отделении и снять наличные по паспорту и книжке. Для рекламы нужен отдельный аккаунт. В моём случае - AdMob. Там всё так же, за исключением первоначального взноса. Но есть один нюанс: после достижения некой пороговой суммы доходов за рекламу будет плашка в аккаунте повешена с предложением вбить адрес для высылки бумажного (sic!) письма с пин-кодом, который должен (после его получения и вбития в аккаунте) убедить AdMob в том, что вы реальный человек. Идёт оно из Калифорнии, готовьтесь к его длительному ожиданию. Сама регистрация не сложная. Просто вбиваем запрашиваемые данные.
Итог: Нужны SIM-карта, банковская карта, паспорт РФ, 30 долларов и чуть-чуть прямых рук.
P.S. Вот тут ещё чуть-чуть информации: Вывод денег из аккаунтов Google Play и AdMob

Код-гольф - Реализация алгоритма выборки комбинаций

Приём ответов завершён, всем спасибо за участие! Можете оставлять свои решения, но победители уже выбраны и пересчёта не будет.

Приветствую.
Задача: Напишите функцию, которая из произвольного входящего массива выберет все комбинации чисел, сумма которых будет равняться 10.
Подробнее: Диапазон чисел: 0 - 1000 включительно. Количество чисел во входящем массиве: 1 - 10 включительно. Уже выбранные числа могут использоваться неоднократно, но комбинации должны быть уникальны. --- Смена позиций не делает комбинацию уникальной, т. е. [1,9] и [9,1] не позволяются). --- При входных данных [5,5,2,3] можно сделать [5,5], [5,2,3] Продолжительность конкурса: 14 дней Обязательный формат метки ответа (для автоматического парсера в таблицу):

Язык, КоличествоСимволов


Определение победителя: Определяется по градации:
Реализация, состоящая из наименьшего количества символов. Реализация, получившая больше всего плюсов (общий рейтинг минус голоса против). Реализация, время первой редакции которой раньше.
Необходимо так же давать ссылку на один из онлайн-компиляторов с Вашим рабочим кодом. Тесты приветствуются. Настоятельно рекомендуется давать как конкурсную версию кода (минифицированную и/или с колдунствами), так и наглядное описание этого же кода. Всем интересно не только увидеть языковую магию, но и что-то почерпнуть для себя.
От одного участника допустимо несколько ответов, если они реализованы на разных языках. Но не более одного на язык

Все вопросы по деталям и/или разногласиям и/или трактовке условий, прошу обсуждать в комментариях к этому сообщению или в комнате чата по код-гольфу

Итоги:
Стандартные 3 места + 1 за самое большое количество плюсов (общий рейтинг минус голоса против).
1 место: @PavelMayorov - Haskell, 42 символа 2 место: @ArtemKonovalov - Scala, 69 символов 3 место: @Mike - Perl, 78 символов
Зрительские симпатии: @D-side (Ruby, 84) - 19 баллов
Поздравления всем участникам, вы хорошо сражались. Особенно страсти накалились в самом конце, когда неожиданно было опубликовано решение обгоняющее лидера на 1 символ. Но судьба вернула всё обратно.
Хотелось бы отметить необычное для данного соревнования решение от пользователя @AlexanderGavrikov - 1437 символов! Это своеобразный рекорд, стоит отметить.

Таблица лидеров:
execute(581668); .cssload-container,.cssload-cube{width:97px;height:97px;transform-style:preserve-3d}.cssload-container,.cssload-cube,.cssload-half1,.cssload-half2{transform-style:preserve-3d}.cssload-container{position:relative;margin:23px 84px;perspective:292px}.cssload-cube{animation:cube 11.5s forwards infinite;transform-origin:center 49px}.cssload-half1,.cssload-s1{top:0;transform-origin:50% 100%}.cssload-half1{height:39px;position:absolute;animation:half-fold 11.5s forwards infinite}.cssload-side{width:19px;height:19px;background:#ddd;position:absolute}.cssload-s1{left:39px;animation:s1ani 11.5s forwards infinite}.cssload-s2,.cssload-s3,.cssload-s4{left:39px;transform-origin:50% 0}.cssload-s2{top:19px;animation:s2ani 11.5s forwards infinite}.cssload-s3{top:39px;animation:s3ani 11.5s forwards infinite}.cssload-s4{top:58px;animation:s4ani 11.5s forwards infinite}.cssload-s5{left:19px;top:19px;transform-origin:100% 50%;animation:s5ani 11.5s forwards infinite}.cssload-s6{left:58px;top:39px;transform-origin:0 50%;animation:s6ani 11.5s forwards infinite}@keyframes cube{0%,30%{transform:rotateX(0)}40%{transform:rotateX(45deg) rotateY(0) rotate(45deg)}60%{transform:rotateX(60deg) rotateY(0) rotate(45deg)}65%,70%{transform:rotateX(60deg) rotate(45deg) rotate(180deg)}75%,80%{transform:rotateX(60deg) rotate(45deg) rotate(1turn)}90%{transform:rotateX(0) rotate(0) rotate(0)}}@keyframes s1ani{0%{opacity:1;transform:translateY(0);background:#ddd}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(-90deg);background:#ddd}90%{transform:rotateX(-90deg)}}@keyframes s2ani{0%{opacity:0;transform:rotateX(-179deg)}10%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%,80%{background:#b4b4b4}65%{opacity:1;background:#b4b4b4}90%{opacity:1}to{opacity:0}}@keyframes s3ani{0%,10%{opacity:0;transform:rotateX(-179deg)}20%,90%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%{background:#969696}to{opacity:0}}@keyframes s4ani{0%,20%{opacity:0;transform:rotateX(-179deg)}10%,to{opacity:0}30%{opacity:1;transform:rotateX(0)}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(90deg);background:#b4b4b4}80%{background:#b4b4b4}90%{opacity:1;transform:rotateX(90deg)}}@keyframes s5ani{0%,10%{opacity:0;transform:rotateY(-179deg)}20%{opacity:1;background:#ddd;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(90deg)}55%{background:#ddd}60%{background:#c8c8c8}90%{transform:rotateY(90deg);opacity:1}to{opacity:0}}@keyframes s6ani{0%,20%{opacity:0;transform:rotateY(179deg)}30%{opacity:1;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(-90deg);background:#ddd}60%,80%{background:#c8c8c8}90%{opacity:1;transform:rotateY(-90deg)}to{opacity:0}}@keyframes half-fold{0%,50%{transform:rotateX(0)}60%,90%{transform:rotateX(-90deg)}} .cssload-container,.cssload-cube{width:97px;height:97px;transform-style:preserve-3d}.cssload-container,.cssload-cube,.cssload-half1,.cssload-half2{transform-style:preserve-3d}.cssload-container{position:relative;margin:23px 84px;perspective:292px}.cssload-cube{animation:cube 11.5s forwards infinite;transform-origin:center 49px}.cssload-half1,.cssload-s1{top:0;transform-origin:50% 100%}.cssload-half1{height:39px;position:absolute;animation:half-fold 11.5s forwards infinite}.cssload-side{width:19px;height:19px;background:#ddd;position:absolute}.cssload-s1{left:39px;animation:s1ani 11.5s forwards infinite}.cssload-s2,.cssload-s3,.cssload-s4{left:39px;transform-origin:50% 0}.cssload-s2{top:19px;animation:s2ani 11.5s forwards infinite}.cssload-s3{top:39px;animation:s3ani 11.5s forwards infinite}.cssload-s4{top:58px;animation:s4ani 11.5s forwards infinite}.cssload-s5{left:19px;top:19px;transform-origin:100% 50%;animation:s5ani 11.5s forwards infinite}.cssload-s6{left:58px;top:39px;transform-origin:0 50%;animation:s6ani 11.5s forwards infinite}@keyframes cube{0%,30%{transform:rotateX(0)}40%{transform:rotateX(45deg) rotateY(0) rotate(45deg)}60%{transform:rotateX(60deg) rotateY(0) rotate(45deg)}65%,70%{transform:rotateX(60deg) rotate(45deg) rotate(180deg)}75%,80%{transform:rotateX(60deg) rotate(45deg) rotate(1turn)}90%{transform:rotateX(0) rotate(0) rotate(0)}}@keyframes s1ani{0%{opacity:1;transform:translateY(0);background:#ddd}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(-90deg);background:#ddd}90%{transform:rotateX(-90deg)}}@keyframes s2ani{0%{opacity:0;transform:rotateX(-179deg)}10%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%,80%{background:#b4b4b4}65%{opacity:1;background:#b4b4b4}90%{opacity:1}to{opacity:0}}@keyframes s3ani{0%,10%{opacity:0;transform:rotateX(-179deg)}20%,90%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%{background:#969696}to{opacity:0}}@keyframes s4ani{0%,20%{opacity:0;transform:rotateX(-179deg)}10%,to{opacity:0}30%{opacity:1;transform:rotateX(0)}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(90deg);background:#b4b4b4}80%{background:#b4b4b4}90%{opacity:1;transform:rotateX(90deg)}}@keyframes s5ani{0%,10%{opacity:0;transform:rotateY(-179deg)}20%{opacity:1;background:#ddd;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(90deg)}55%{background:#ddd}60%{background:#c8c8c8}90%{transform:rotateY(90deg);opacity:1}to{opacity:0}}@keyframes s6ani{0%,20%{opacity:0;transform:rotateY(179deg)}30%{opacity:1;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(-90deg);background:#ddd}60%,80%{background:#c8c8c8}90%{opacity:1;transform:rotateY(-90deg)}to{opacity:0}}@keyframes half-fold{0%,50%{transform:rotateX(0)}60%,90%{transform:rotateX(-90deg)}} /* TODO: Fix it */ body { font-size: 1rem; line-height: 1.5rem; font-family: 'Open Sans', sans-serif; background: #fff; padding: 0 2rem; } h1 { font-weight: 600; margin-bottom: 3rem; text-align: center; color: #212121; } #leadership { width: 100%; margin: 1rem auto; border-collapse: collapse; box-shadow: 0 2px 7px rgba(0,0,0,0.2); background: #fafafa; } #leadership td { padding: 1rem .5rem !important; text-align: left; font-weight: 500; transition: all .3s ease-in-out; } #leadership tr:hover td{ background: #03a9f4; color: #fefefe; } #leadership tr:hover td a { color: #fff; } #leadership th { padding: 1.5rem .5rem !important; color: #727272; text-align: left !important; font-weight: 500; border-bottom: 1px solid #dcdcdc; } #leadership a { text-decoration: none; color: #212121; } #leadership a:hover { color: #03a9f4; } #leadership td:nth-of-type(1){ text-align: center; color: #727272; font-size: .75rem; } #leadership td:nth-of-type(2){ } #leadership td:nth-of-type(2) img { width: 34px; border-radius: 50%; } /* #leadership th:nth-of-type(1), #leadership th:nth-of-type(2){ border-bottom: none; } */ #leadership th:nth-of-type(5), #leadership th:nth-of-type(6), #leadership th:nth-of-type(7), #leadership td:nth-of-type(5), #leadership td:nth-of-type(6), #leadership td:nth-of-type(7) { text-align: center !important; }

Удачи всем!


Ответ

Haskell, 42 70 символа
g=nub.filter((10==).sum).subsequences.sort
Требует импорта функций nub, sort и subsequences из Data.List
Запуск: main = print $ g [5,5,2,3] http://ideone.com/5jUIsy
Как работает:
входной список сортируется (иначе функция nub, см. далее, не поймет); функция subsequences находит все сочетания (без ограничения длины), их 2m, где m - длина входного списка; при помощи filter выбираются те сочетания, которые дают нужную сумму; при помощи nub выбираются различные сочетания.
PS спасибо участнику Artem Konovalov за то, что опосредованно подсказал мне не писать велосипед, а заглянуть в стандартную библиотеку языка :)

Отображение числа 9223372036854775807

Почему разные языки по-разному отображают число 9223372036854775807, хотя все используют один и тот же формат 8-байтного double для представления чисел?
9223372036854775807 - в коде 9223372036854775808 - C++ http://ideone.com/PV5iPg и http://codepad.org/vhQzDMqT 9223372036854776000 - Javascript https://jsfiddle.net/5ugL4rqh/ 9223372036854776000 - Java http://ideone.com/QtXRWi 9223372036854780000 - C# http://ideone.com/36Lzzi


Ответ

Здесь в каждой среде/языке два преобразования:
Из константы в исходном коде в объект в памяти Печать этого объекта памяти выбранным способом.
C++
Эффект от кода из вопроса для С++: volatile double x = 9223372036854775807.; схож с gcc's -ffloat-store опцией и позволяет забыть о возможных дополнительных битах и думать только о 64-битных IEEE 754 числах двойной точности, используемые в рассматриваемой реализации (IEEE 754 не обязателен, но конкретная реализация для float чисел должна быть задокументирована).
Константа 9223372036854775807. из исходного кода превращается в 9223372036854775808. double (ожидаемо для этого типа, см. демонстрацию битового представления внизу). В CPython тоже самое происходит:

>>> 9223372036854775807. .as_integer_ratio() (9223372036854775808, 1) >>> 9223372036854775807. .hex() '0x1.0000000000000p+63'
то есть 9223372036854775807. не может быть точно представлено в IEEE 754 double и поэтому используется приближение 9223372036854775808. (263), которое уже выводится точно в этом случае с помощью: cout << fixed << x; как ascii-строка: "9223372036854775808.000000" (в C локали).
Как double в памяти и в виде бит в IEEE 754 представлен, и как печать может происходить в С, подробно описано в ответе на вопрос printf как средство печати переменных в С
В данном случае, так как число является степенью двойки, то легко найти его IEEE 754 представление:
d = ±знак · (1 + мантисса / 252) · 2порядок − 1023
знаковый бит равен нулю, так как число положительное порядок = (63 + 1023)10 = 100001111102, чтобы получить 263 у мантисса все явные 52 бита нулевые (старший неявный 53ий бит всегда равен единице)
Все биты числа вместе:
0 10000111110 0000000000000000000000000000000000000000000000000000
Что подтверждается вычислениями на Питоне:
>>> import struct >>> struct.pack('>d', 9223372036854775808.0).hex() 43e0000000000000 >>> bin(struct.unpack('>Q', struct.pack('>d', 9223372036854775808.0))[0])[2:].zfill(64) '0100001111100000000000000000000000000000000000000000000000000000'
И в обратную сторону:
>>> b64 = 0b0_10000111110_0000000000000000000000000000000000000000000000000000 .to_bytes(8, 'big') >>> b64.hex() '43e0000000000000' >>> "%f" % struct.unpack('>d', b64)[0] '9223372036854775808.000000'
Порядок байт в памяти у числа в примере показан от старшего к младшему (big-endian), но фактически может быть и от младшего к старшему (little-endian):
>>> struct.pack('d', 9223372036854775808.0).hex() '000000000000e043'
Можно посмотреть, что не подряд идут представимые числа, вычитая/прибавляя по одному биту к мантиссе:
>>> x = 0b0_10000111110_0000000000000000000000000000000000000000000000000000
>>> def to_float_string(bits): ... return "%f" % struct.unpack('>d', bits.to_bytes(8, 'big'))[0]
>>> for n in range(x-1, x+2): ... print(to_float_string(n)) 9223372036854774784.000000 9223372036854775808.000000 9223372036854777856.000000
Разница в один бит для чисел этой величины ведёт к разнице больше тысячи в десятичном представлении: ..4784, ..5808, ..7856
Можно воспользоваться C99 функцией nextafter()
#include #include #include
int main(void) { volatile double x = 9223372036854775808.0; printf("%f
", nextafter(x, DBL_MIN)); printf("%f
", x); printf("%f
", nextafter(x, DBL_MAX)); }
Результаты совпадают с предыдущими:
9223372036854774784.000000 9223372036854775808.000000 9223372036854777856.000000
Javascript
Числа в JavaScript представлены интересным способом — целые как IEEE 754 double представлены. К примеру, максимальное число (Number.MAX_SAFE_INTEGER) равно 253
9223372036854775807 на три порядка больше MAX_SAFE_INTEGER поэтому нет гарантии, что n и n+1 представимы.
> 9223372036854776000 === 9223372036854775807 true > 9223372036854775808 === 9223372036854775807 true
9223372036854776000 (результат document.write(9223372036854775807) в одной из javascript реализаций) допустим cтандартом в качестве строкового представления для 9223372036854775807 (это по-прежнему одно binary64 число: 0x1.0000000000000p+63).
Результаты побитовых операций вообще ограничены 32-битными числами со знаком. Можно посмотреть на какие ухищрения пришлость пойти, чтобы воспроизвести результат хэш-функции, реализованной в javascript: Как перевести из Javascript в Питон функцию хэширования строки
Java
В Java, double это тип со значениями, которые включают 64-bit IEEE 754 числа с плавающей точкой.
double x = 9223372036854775807.; System.out.format("%f", x);
Возможная логика, почему 9223372036854776000, а не 9223372036854775808. десятичное представление выбрано для binary64 числа 0x1.0000000000000p+63 в том, что в общем случае это позволяет меньше цифр печатать для дробных чисел — не отображаются завершающие нули (это спекуляция — я не углублялся в этот вопрос).
C#
msdn утверждает что double в C# соотвествует IEEE 754.
9223372036854780000.0 намекает, что Console.WriteLine("{0:0.0}", x); округляет до 15 цифр при печати. Напечатанное число отличается от x
>>> 9223372036854780000. .hex() '0x1.0000000000002p+63'
Вероятно это происходит по cхожей причине, что и 0.1 показывается как 0.1 при печати, а не 0.10000000000000001 или вообще 0.1000000000000000055511151231257827021181583404541015625 ( 0.1 .hex() == '0x1.999999999999ap-4'). Более того binary64 представление другое (263 vs. 263+212) (единственный из представленных примеров в вопросе, который по умолчанию не выводит эквивалентное представление).
Возможно, приоритет в округлении до 15 цифр, не обращая внимание достаточно ли это, чтобы эквивалентное binary64 представление получить. Не только C# себя так ведёт, к примеру, numpy.array в Питоне выводит по умолчанию 8 цифр:
>>> import numpy >>> a = numpy.array([2**63-1, 2**63, 2**63+2**12], dtype=numpy.float64) >>> a array([ 9.22337204e+18, 9.22337204e+18, 9.22337204e+18]) >>> 9.22337204e+18 .hex() '0x1.0000000176f0ap+63' >>> numpy.set_printoptions(precision=16) >>> a array([ 9.2233720368547758e+18, 9.2233720368547758e+18, 9.2233720368547799e+18])
Показ 17 цифр в C# возможен с помощью стандартного "{0:R}" формата, что выводит 9.2233720368547758E+18, то есть снова ту же рассматриваемую изначальную 263 степень получили:
>>> 9.2233720368547758E+18 .hex() '0x1.0000000000000p+63'

Перевести программу с Паскаля на [любой-язык]

Конкурс окончен, смотрите результаты в конце вопроса.

Я думаю, многие из вас видели вопросы, состоящие из просьбы перевода программы с одного языка на другой. Давайте-ка покажем, как делать такие вещи правильно! В нашем конкурсе мы исходим из такой простой программы на Паскале:
program test; var a, b, c: integer; begin readln(a); readln(b); c := a + b; writeln(c); end.
(Она же на ideone.)
Задание состоит в следующем: вы должны перевести программу на любой-язык так, чтобы сохранить как можно больше от исходного текста программы. В качестве целевого языка, понятно, исключаются языки группы Паскаля (Delphi, Algol, Oberon, Modula, etc., все языки, в которых используется begin/end для группировки команд в составную команду).
Вы можете дописывать конструкции до и после данного в условии текста, но не внутри его (точнее, можете и внутри, но это будет считаться изменением — смотрите ниже условия подсчёта). Сам текст желательно менять как можно меньше.
Ограничения: Строки исходной программы между begin и end должны сохранять свой смысл. Они должны выполняться, и при их выполнении должно происходить в общих чертах то же, что и в исходной программе: readln должно считывать значения с консоли, c := a + b должно складывать значения двух переменных (или что там есть в вашем языке) в третью, writeln должно выводить правильный результат на консоль. (Это означает, что вы не можете просто закомментировать код первоначальной программы.)
Определение победителя: Выигрывает код, в котором исходный текст менее всего изменён по сравнению с полным первоначальным вариантом (количество добавленных символов + количество удалённых символов + количество изменённых символов), считая и строки с program и end.. Разница в больших/маленьких буквах, а также замена символа на одинаковый по начертанию (например, русское «с»/английское «c») считается за пол-символа. Если два решения имеют одинаковое количество отличий (например, ноль), выигрывает то, у которого меньше добавленного кода (в символах). Если несколько решений одинаковы и по этому критерию, выигрывает то решение, которое получит больше голосов (как обычно, «за» минус «против»).
В частности, полное совпадение кода выигрывает у неполного независимо от количества подготовительного кода.
Для того, чтобы было легче проверять ваш код, старайтесь публиковать ссылку на онлайн-компилятор с вашим кодом. Код должен компилироваться без ошибок (пусть даже с предупреждениями) и правильно работать в диапазоне входных чисел от 0 до 1000.
Продолжительность конкурса — 1 неделя.

Для исключения разночтений, при неясности в правилах пожалуйста переспрашивайте в комментариях или в чате, посвящённом code golf

Для примера, вот внеконкурсное решение на plain TeX:

ewcount\tmp
ewcount\c
\def\uncatcodeletters{\uncatcoderange{`a}{`z}\uncatcoderange{`A}{`Z}} \def\uncatcoderange#1#2{% \tmp=#1 \advance\tmp -1 \loop\advance\tmp 1 \expandafter\catcode
umber\tmp=11 \ifnum\tmp<#2
epeat}
\def\s{\begingroup\uncatcodeletters\shlp} {\def~ := #1 + #2;{% \global\expandafter\c\csname #1\endcsname \global\expandafter\advance\expandafter\c\csname #2\endcsname \endgroup} \global\let\shlp=~}
\def\inp{\begingroup\uncatcodeletters\inphelper} \def\inphelper eadln(#1);{\endlinechar=-1 \escapechar=-1 \expandafter\inphelperi\csname #1\endcsname\endgroup} \def\inphelperi{\global
ead16 to }
\def\out{\begingroup\uncatcodeletters\outhelper} \def\outhelper riteln(#1);{\message{\expandafter\the\csname #1\endcsname}\endgroup}
\let\DEF\def \let\END\end \catcode`r=13 \let r=\inp \catcode`w=13 \let w=\out \catcode`p=14 \catcode`v=14 \catcode`b=14 \let~=\catcode ~`c=13 \let c=\s ~`e=13 \DEF end.{\END}
program test; var a, b, c: integer; begin readln(a); readln(b); c := a + b; writeln(c); end.
(Если кому интересно, гольфированный вариант.) Транскрипт компиляции:
~>tex golf.tex This is TeX, Version 3.14159265 (MiKTeX 2.9 64-bit) (golf.tex a=5 % <-- 5 введено с консоли
b=8 % <-- 8 введено с консоли 13 ) No pages of output. Transcript written on golf.log.

Просьба к отвечающим писать в начале решения ваш язык, количество изменённых символов и количество символов в подготовительном коде. Также просьба давать не более одного решения на ответ.

Обновление: Конкурс окончен, вот результаты.
Побеждает ответ @Mike, сумевший уложиться в 78 подготовительных символов, и не поменять ни символа в исходном коде.
Другой ответ того же автора выглядит чрезвычайно изящно (подключение паскалевского синтаксиса как внешний модуль, хей!), и почти выиграл приз зрительских симпатий, но проигрывает по количеству символов вследствие своей большей общности. Оба решения пользуются особенностью языка Perl, который в своих модулях позволяет предобработку текста на Perl самим Perl'ом. Мощный язык, мощные средства управления синтаксисом, заслуженная победа.
Второй в списке победителей — ответ @Qwertiy. Это решение продолжает идею «получить текст как строку, обработать, чтобы получился код на нужном языке, и выполнить над ней eval», с симпатичной, очень техничной и компактной реализацией (регулярки!).
Приз зрительских симпатий получает неожиданный ответ @kmv. В этом решении текст исходной программы не объявляется строкой, а «вытягивается» из кода функции! (Это, формально говоря, решение не по стандарту, но фактически в распространённых браузерах toString() работает именно так.)
Третье место получает решение @pavel с комбинацией Unix shell/C, которое обходится без eval за счёт замены строк до компиляции и использования препроцессора C. Такой подход позволяет справиться с двоеточиями, которые вызывают затруднения для препроцессора у чистых решений на C/C++.
Вообще, идея со строкой и eval оказалась наиболее популярной, её реализуют также ответы @edem Perl, построчная замена, практически интерпретация, @Red Skotina (замена строк на Питоне, построчная адаптация текста, оставаясь в рамках правил, хотя и на грани), @gil9red (то же, но более универсально, Питон), @nuts119 на C# (да, в C# можно сделать eval, вы не знали?) и @Streletz на Java (интерпретатор из сторонней библиотеки).
Тему интерпретации продолжает ещё одно решение @nuts119 на C# с использованием DataTable как arithmetic engine. Это решение, при всей его сложности, имеет дальний прицел на построение полноценного интерпретатора.
Оставшиеся решения на чистом C/C++ и Javascript/Typescript без eval вынуждены модифицировать исходный текст, хотя они смогли обойтись минимальным количеством изменений. Из этих решений наилучшие с одним удалённым символом решения @kmv (C, препроцессор, использование битовых полей) и @Qwertiy (C++, тонкости препроцессора). Интересно, что эти оба решения убирают из исходного текста соседние символы: из := убрано в первом случае двоеточие, а во втором — знак = (!).
Оставшиеся четыре решения (@Qwertiy, typescript, @pavel, C++, препроцессор (заработало больше голосов, чем победитель), снова @Qwertiy, javascript и @Grundy, C, препроцессор) меняют больше символов в исходном коде, но также интересны и стоят вашего внимания.
Большое спасибо всем, кто принимал участие в конкурсе!

Таблица лидеров: (спасибо @Grundy за адаптацию скрипта и @jfs за идею)
function getAnswers(questionId, answer_filter, page) { return jQuery.ajax({ url: '//api.stackexchange.com/2.2/questions/' + questionId + '/answers?page=' + page + '&pagesize=100&order=desc&sort=activity&site=ru.stackoverflow&filter=' + answer_filter, method: "get", dataType: "jsonp", crossDomain: true }).then(function(data) { if (data.has_more) { return getAnswers(questionId, answer_filter, page + 1).then(function(d) { return data.items.concat(d.items); }) } return data.items; }); } function getAuthorName(e) { return e.owner.display_name } function process(items) { return items.map(function(item) { var matched = item.body.match(/\s*(.+?)\s*?,.*?(\d+),.*?(\d+)\s*?(?:[.;,(].*)?<\/h/); if (matched) { return { lang: matched[1], setup: +matched[2], changes: +matched[3], link: item.share_link, author: getAuthorName(item) }; } else { return { lang: "N/A", setup: "N/A", changes: "N/A", link: item.share_link, author: getAuthorName(item) } } }); } function sort(items) { return items.sort(function(a, b) { if (a.lang == "N/A") return 1; if (a.changes != b.changes) return a.changes - b.changes; return a.setup - b.setup; }) } function fillTemplate(sortedItems) { $('#leadership').append(sortedItems.map(function(item, index) { return $('').append($('').html(index + 1)) .append($('').html(item.author)) .append($('').html(item.lang)) .append($('').html(item.setup)) .append($('').html(item.changes)) .append($('').append($('').attr('href', item.link).text('Link'))); })); return sortedItems; } var QUESTION_ID = 526265, ANSWER_FILTER = "!4*SyY(4Kifo3Mz*lT", startPage = 1; getAnswers(QUESTION_ID, ANSWER_FILTER, startPage) .then(process) .then(sort) .then(fillTemplate); #leadership { border-collapse: collapse; } #leadership td, #leadership th { padding: 5px; } #leadership th { text-align: center; }

Таблица лидеров

Автор Язык Подготовка Изменено


Ответ

Раз в конкурсе участвует размер, вот еще вариант (лично мне нравится меньше, потому как большая ориентировка именно на этот код):
perl, подготовка 97, измененных 0
perl, подготовка 78, измененных 0
sub r{$_[0]=<>} sub wr{print@_} $_=q.
program test; var a, b, c: integer; begin readln(a); readln(b); c := a + b; writeln(c); end.
;s/\b(\w)\b/\$$1/g ;s/^\S.*|.{4}n|://gm ;eval
Тест на ideone
В коде происходит:
Создаем функции r/wr аналогичные по действию паскалевским read/write ln. $_=q. присваивает "переменной по умолчанию" весь текст до следующего знака . Все последующие строки работают с этой "переменной по умолчанию", так как явных переменных в них не указано. Перед переменными (однобуквенными словами) ставим знак $ Удаляем строки program, var, begin, end, части названий функций (readln=r, writeln=wr), двоеточия Выполняем полученный текст:
r($a); r($b); $c = $a + $b; wr($c);

Есть ли в Python оператор switch case?

Столкнулся с тем, что требуется реализовать множественное условие, которое в других языках я бы реализовал с помощью конструкции switch-case.
В Python мне приходится расписывать всё через условия if-elif-else. Это мне кажется довольно неудобным.
Есть ли более удобный способ записи подобных условий?
Например, у меня есть единицы измерения и в зависимости от выбранной мне нужно вернуть соответствующий множитель:
def get_multiplier(unit): if unit == 'mm': return 10**-3 if unit == 'cm': return 10**-2 if unit == 'dm': return 10**-1 if unit == 'm': return 1 if unit == 'km': return 10**3 raise ValueError('Undefined unit: {}'.format(unit))


Ответ

Для начала, ничего особенно плохого в использовании конструкции if-elif-else нет
При желании можно найти несколько альтернатив.

Использование словарей
Довольно распространённый способ организации конструкции switch-case в Python — это использование словаря. Проще показать на примере:
unit_to_multiplier = { 'mm': 10**-3, 'cm': 10**-2, 'dm': 10**-1, 'm': 1, 'km': 10**3 }
Для того, чтобы получить нужный множитель в этом случае требуется лишь взять значение по ключу:
try: mult = unit_to_multiplier['cm'] except KeyError as e: # можно также присвоить значение по умолчанию вместо бросания исключения raise ValueError('Undefined unit: {}'.format(e.args[0]))
Если вы твёрдо уверены, что значение всегда будет присутствовать в словаре, можете опустить блок try-except и быть готовым ловить исключение в другом месте.
Некоторой вариацией этого подходя будет предварительная проверка значения в условии:
if unit in unit_to_multiplier: mult = unit_to_multiplier[unit] else: # обработка отсутствия значения в словаре
В Python принято использовать подход, звучащий примерно так: "лучше попробовать и получить ошибку, чем каждый раз спрашивать разрешение", поэтому более предпочтительный подход с использованием исключений.
Если хочется использовать значение по умолчанию в случае, если ключ отсутствует, удобно использовать метод get
mult = unit_to_multiplier.get('ultra-meter', 0)
Если словарь вам требуется один раз, можно объединить эти выражения в одно:
unit_to_multiplier = { 'mm': 10**-3, 'cm': 10**-2, 'dm': 10**-1, 'm': 1, 'km': 10**3 }.get('km', 0)

На этом возможности этого подхода не заканчиваются. Можно использовать условные выражения в качестве ключей словаря:
def get_temp_description(temp): return { temp < -20: 'Холодно', -20 <= temp < 0: 'Прохладно', 0 <= temp < 15: 'Зябко', 15 <= temp < 25: 'Тепло', 25 <= temp: 'Жарко' }[True]
Этот словарь после вычисления будет иметь два ключа True и False. Нас интересует ключ True. Будьте внимательны, что условия не перекрываются!
Подобные словари могут проверять произвольное свойство, например, тип (источник примера):
selector = { type(x) == str : "it's a str", type(x) == tuple: "it's a tuple", type(x) == dict : "it's a dict" }[1] # можно использовать число 1 как синоним True
При необходимости более сложных действий хранить функцию в качестве значения по каждому ключу:
import operator
operations = { '+': operator.add, '*': lambda x, y: x * y, # ... }
def calc(operation, a, b): return operations[operation](a, b)
Будьте внимательны при использовании словаря с функциями — убедитесь, что вы не вызываете эти функции внутри словаря, а передаёте по ключу; иначе все функции будут выполняться каждый раз при конструировании словаря.

Другие способы
Приведены скорее для ознакомления, чем для реального использования.
Использование функций с шаблонными именами
Создадим класс, в котором напишем несколько методов вида:
def process_first(self): ...
def process_second(self): ...
...
И один метод-диспетчер:
def dispatch(self, value): method_name = 'process_' + str(value) method = getattr(self, method_name) return method()
После этого можно использовать метод dispatch для выполнения соответствующей функции, передавая её суффикс, например x.dispatch('first') Использование специальных классов
Если есть желание использовать синтаксис switch-case в максимально похожем стиле, можно написать что-то вроде следующего кода
class switch(object): def __init__(self, value): self.value = value # значение, которое будем искать self.fall = False # для пустых case блоков
def __iter__(self): # для использования в цикле for """ Возвращает один раз метод match и завершается """ yield self.match raise StopIteration
def match(self, *args): """ Указывает, нужно ли заходить в тестовый вариант """ if self.fall or not args: # пустой список аргументов означает последний блок case # fall означает, что ранее сработало условие и нужно заходить # в каждый case до первого break return True elif self.value in args: self.fall = True return True return False
Используется следующим образом:
x = int(input())
for case in switch(x): if case(1): pass if case(2): pass if case(3): print('Число от 1 до 3') break if case(4): print('Число 4') if case(): # default print('Другое число') Использование операторов and и or
Довольно небезопасный способ, см. пример:
# Условная конструкция
Select Case x Case x<0 : y = -1 Case 0<=x<1 : y = 0 Case 1<=x<2 : y = 1 Case 2<=x<3 : y = 2 Case Else : y = 'n/a' End Select
# Эквивалентная реализация на Python
y = (( x < 0 and 'first segment') or (0 <= x < 1 and 'second segment') or (1 <= x < 2 and 'third segment') or (2 <= x < 3 and 'fourth segment') or 'other segment')
Этот способ использует короткую схему вычисления операторов and и or, т.е. то, что логические выражения вычисляются следующим образом:
(t вычисляющееся как True, f вычисляется как False):
f and x = f t and x = x f or x = x t or x = t
Предложенный способ вычислений будет работать только в том случае, если второй аргумент оператора and всегда будет содержать True-выражение, иначе этот блок всегда будет пропускаться. Например:
y = (( x < 0 and -1) or (0 <= x < 1 and 0) or (1 <= x < 2 and 1) or (2 <= x < 3 and 2) or 'n/a')
Будет работать неправильно в случае 0 <= x < 1, т.к. выражение 0 <= x < 1 and 0 равно 0, и из-за этого управление перейдёт следующему аргументу or, вместо того, чтобы вернуть этот ноль в качестве результата выражения. Использование исключений
Если объявить несколько функций:
import sys
class case_selector(Exception): def __init__(self, value): # один обязательный аргумент Exception.__init__(self, value)
def switch(variable): raise case_selector(variable)
def case(value): exc_сlass, exс_obj, _ = sys.exc_info() if exc_сlass is case_selector and exс_obj.args[0] == value: return exс_class return None
Здесь используется функция sys.exc_info, которая возвращает набор из информации об обрабатываемом исключении: класса, экземпляра и стека.
Код с использованием этих конструкций будет выглядеть следующим образом:
n = int(input()) try: switch(n) except ( case(1), case(2), case(3) ): print "Число от 1 до 3" except case(4): print "Число 4" except: print "Другое число"

Книги и учебные ресурсы по фундаментальным знаниям и навыкам разработчика

Рекомендуемая литература и документация по знаниям и навыкам разработки, не привязанным к конкретным языкам и платформам.
Все эти книги следовало бы добавить в каждый список литературы, но мы следуем принципу DRY и сохраняем их здесь, в одном месте.
Дополнения к ответу всячески приветствуются!

Данный перечень входит в поддерживаемый сообществом Сборник учебных ресурсов по программированию


Ответ

Архитектура ПО
Structure and Interpretation of Computer Programs - 2nd Edition. Harold Abelson, Gerald Jay Sussman, Julie Sussman
Русский перевод: Структура и Интерпретация Компьютерных Программ. Харольд Абельсон, Джеральд Джей Сассман
Алгоритмы и структуры данных
The Algorithm Design Manual. Steven S Skiena. 2008
Русский перевод: Алгоритмы. Руководство по разработке. Стивен Скиена. 2014 г. Introduction to Algorithms, 3rd Edition. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein. 2009
Русский перевод: Алгоритмы. Построение и анализ. Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн. 2015 г. The Art of Computer Programming. Donald E. Knuth. 2011
Русский перевод: Искусство программирования. Дональд Э. Кнут. 2015 г. Algorithms + Data Structures = Programs. Niklaus Wirth, 1976 (or Algorithms + Data Structures. 2004.
Русский перевод: Алгоритмы + структуры данных = программы. М.: Мир, 1985, Алгоритмы и структуры данных. М.: Мир, 1989, Алгоритмы и структуры данных. Новая версия для Оберона. М.: ДМК Пресс, 2010. Старая версия книги, в отличие от новых, содержит подробно разобранный компилятор простого языка.
Проектирование и стиль кода
Design Patterns: Elements of Reusable Object-Oriented Software. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
Русский перевод: Приёмы объектно-ориентированного проектирования. Паттерны проектирования. Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидс Patterns of Enterprise Application Architecture. Martin Fowler
Русский перевод: Архитектура корпоративных программных приложений. Мартин Фаулер Domain-Driven Design: Tackling Complexity in the Heart of Software. Eric Evans
Русский перевод: Предметно-ориентированное проектирование. Структуризация сложных программных систем. Эрик Эванс «Совершенный код» (Code Complete). Стив Макконнелл «Рефакторинг. Улучшение существующего кода». Мартин Фаулер «Чистый код. Создание, анализ и рефакторинг» (Clean Code: A Handbook of Agile Software Craftsmanship). Роберт Мартин
Навыки разработчика
Эндрю Хант, Дэвид Томас — «Программист-прагматик. Путь от подмастерья к мастеру»
Организация процесса разработки
Том ДеМарко — «Deadline. Роман об управлении проектами» Роберт Мартин — «Быстрая разработка программного обеспечения» Джоэл Спольски — «И снова о программировании». Джо Мараско — «IT-проекты. Фронтовые очерки» Стив Макконнелл — «Сколько стоит программный проект» Джин Ким, Кевин Бер, Джордж Спаффорд — «Проект «Феникс». Роман о том, как DevOps меняет бизнес к лучшему».
Синтаксический разбор и компиляция
Compilers: Principles, Techniques, and Tools, Alfred V. Aho, Monica S. Lam, Ravi Sethi, Jeffrey D. Ullman
Русский перевод: Компиляторы: принципы, технологии и инструментарий, Альфред Ахо, Моника С. Лам, Рави Сети, Джеффри Ульман. Известна как «Книга Дракона».

Наглядный пример различия DTO, POCO (POJO) и Value Object

Навеяно статьёй о различиях DTO, POCO и Value Object на Хабрахабре: DTO vs POCO vs Value Object, а также вопросом POCO vs DTO
Нигде нет конкретных примеров. Приведите, пожалуйста, конкретный пример с небольшим описанием (или также примером), где и как его использовать и для чего.
UPD
Отличные ответы. Всем спасибо.
Еще небольшой вопрос по использованию POCO. Когда и насколько рационально запихивать логику в объекты? Вот к примеру, у меня есть сервисный слой, который возвращает POCO, какие именно методы я туда могу вставить? Допустим, мне нужно валидировать Кастомера, ок, я сделал в POCO метод Validate, пока мне не нужно лезть для валидации в базу - все хорошо, но как только это понадобиться, идея уже не кажется такой хорошей. Или я не прав? Сейчас у меня приложение, где почти все действия выполняет бизнес слой, в моделях только простые методы типа GetFullName, и по сути я оперирую DTO-хами. Так вот, как уследить ту тонкую грань "что в POCO, что в сервисе" или вообще "всю логику в сервисы, оперировать DTO"?


Ответ

Представим некоторый интернет магазин. У этого магазина есть веб-интерфейс и сервер приложений, который обрабатывает логику. Некий пользователь хочет совершить какой-нибудь заказ. Для этого ему нужно выполнить ряд действий: добавить нужные товары в корзину и подтвердить заказ.
Для того, чтобы это сделать, на сервере приложений может существовать класс Order
public class Order { private ItemDiscountService _itemDiscountService; private UserService _userService;
public Order(ItemDiscountService itemDiscountService, UserService userService) { _itemDiscountService = itemDiscountService; _userService = userService }
public int Id { get; set; } public List Items { get; set; } public decimal Subtotal { get;set; } public decimal Discount { get; set; }
public void AddItem(Item item) { Items.Add(item); CalculateSubtotalAndDiscount(); }
public void CalculateSubtotalAndDiscount() { decimal subtotal = 0; decimal discount = 0; foreach (var item in Items) { var currentCost = item.Cost * _itemDiscountService.GetDiscountFactor(item) * _userService.GetCurrentUserDiscountFactor(); subtotal += currentCost; discount += item.Cost - currentCost; }
Subtotal = subtotal; Discount = discount; } }
Этот класс содержит в себе данные и логику их изменения. Он не унаследован от какого-либо специфического класса из сторонней библиотеки или от какого-либо стороннего класса и является достаточно простым - Plain Old CLR/Java Object

Когда пользователь добавляет что-то в корзину, эта информация передаётся на сервер приложений, что вызывает метод AddItem в классе Order, который пересчитывает стоимость товаров и скидку, меняя тем самым состояние заказа. Нужно отобразить пользователю это изменение, и для этого нужно передать обновлённое состояние обратно на клиент.
Но мы не можем просто передать экземпляр нашего Order или его копию, так как он зависит от других классов (ItemDiscountService, UserService), которые в свою очередь могут зависеть от других классов, которым может быть нужно соединение с базой данных и т. п.
Конечно, их можно продублировать на клиенте, но тогда на клиенте будет доступна вся наша логика, строка подключения к БД и т. п., чего мы показывать совершенно не хотим. Поэтому, чтобы просто передать обновленное состояние, мы можем сделать для этого специальный класс:
public class OrderDto { public int Id { get; set; } public decimal Subtotal { get; set; } public decimal Discount { get; set; } public decimal Total { get; set; } }
Мы сможем поместить в него те данные, которые хотим передать на клиент, создав тем самым Data Transfer Object. В нем могут содержаться совершенно любые нужные нам атрибуты. В том числе и те, которых нет в классе Order, например, атрибут Total

У каждого заказа есть свой идентификатор - Id, который мы используем для того, чтобы отличать один заказ от другого. В то время как в памяти сервера приложений может существовать заказ с Id=1, содержащий в себе 3 предмета, в БД может хранится такой же заказ, с тем же идентификатором, но содержащий в себе 5 предметов. Такое может возникнуть, если мы прочитали состояние заказа из БД и поменяли его в памяти, не сохранив изменения в БД.
Получается, что несмотря на то, что некоторые значения у заказа в БД и заказа в памяти сервера приложений будут отличаться, это все равно будет один и тот же объект, так как их идентификаторы совпадают.
В свою очередь значение стоимости - 100, номер идентификатора - 1, текущая дата, имя текущего пользователя - "Петрович" будут равны аналогичным значениям только тогда, когда эти значения будут полностью совпадать, и никак иначе.
Т. е. 100 может быть равно только 100, "Петрович" может быть равен только "Петрович" и т. д. И неважно, где будут созданы эти объекты. Если их значения будут полностью совпадать - они будут равны. Такие объекты называются Value Object
Помимо уже существующих Value Object типа decimal или string можно создавать и свои. В нашем примере мы могли бы создать тип OrderPrice и поместить туда поля Subtotal, Total и Discount.
public struct OrderPrice { public decimal Subtotal; public decimal Discount; public decimal Total; }
В c# есть подходящая для этого возможность создавать значимые типы которые сравниваются по значению и при присваивании целиком копируются.

UPDATE Что касается обновленного вопроса (хоть это действительно отдельный большой вопрос, как заметил Discord):
Когда мы разрабатываем приложение мы работаем с какой-либо предметной областью. Эта предметная область может быть выражена в виде некоторой модели и действий, которые меняют состояние этой модели. Все это может быть представлено в виде набора классов. Такие классы содержат в себе как данные (в виде полей классов) так и действия, которые этими данными манипулируют (в виде методов).
В принципе нет никаких ограничений на размещение данных или методов по классам. Можно вообще все засунуть в один класс и это будет прекрасно работать. Основная проблема заключается в том, что такой код будет сложнее, а значит дороже поддерживать. Так как все будет переплетено между собой - любые изменения могут привносить кучу ошибок и т.п. Поэтому, для достижения более "дешевого" кода мы начинаем его как-то структурировать, разбивать на модули и т.п.
Мы можем разложить данные в одни классы, а методы в другие и это тоже будет работать и будет даже более модульно. Но все равно может нести ряд минусов. Глядя на кучу данных может быть не очевидным то, что вообще с ними может происходить или кому они могут быть нужны. Тоже самое и с кучей методов. Поэтому, чтобы было еще удобнее можно разложить данные по классам как-то сгруппировав их понятным образом. Тоже самое и с методами. Данные заказа, пользователя, товара и т.п. могут стать отдельными классами так же как и классы с соответствующими методами. Это будет еще модульнее и понятнее. Но у любого подхода есть свои плюсы и минусы.
Например, в нашем интернет магазине есть различные товары, логика расчета цены которых может быть достаточно сложной. Представим, что есть некий базовый класс Item, и множество производных классов:
public class Item { public int Id {get;set;} public string Name {get;set;} public decimal BaseCost {get;set;} public decimal Cost {get;set;} }
public class Boots : Item { ... } public class Shirt : Item { ... } public class Pants : Item { ... }
Так как логика у нас находится в отдельных классах, представим что есть класс ItemCostService, который умеет рассчитывать стоимость товара. Тогда, из-за наличия большого числа различных условий он может выглядеть как-то так:
public class ItemCostService { public decimal CalculateCost(Item item) { if(item is Boots) { item.Cost = ... } else if (item is Shirt) { item.Cost = ... } else if .... } }
И таких мест в программе, где в зависимости от конкретного типа товара должно быть различное поведение может быть много. Конечно, это все будет работать. Но, как только у нас появляется новый тип товара, или поменяется логика обработки существующего типа товара нам придется изменить код в большом количестве мест везде, где присутствуют такие условия. Это сложнее, чем поменять все в одном месте, дольше и чревато тем, что можно что-то забыть сделать.
В данном вопросе мы говорим о языках, основной парадигмой которых является ООП. А это значит, что существует готовая инфраструктура которая поддерживает основные принципы ООП. Чтобы следовать этой парадигме и получать выгоду от готовой инфраструктуры мы можем поменять наши класс, добавив логику вычисления стоимости в них, меняя ее по необходимости в производных классах:
public class Item { ... public virtual void CalculateCost() { ... } }
public class Boots : Item { public override void CalculateCost() { ... } }
Каждый производный тип сам сможет определить логику своего поведения. Вся она будет в одном месте, рядом с данными. А какой из конкретных методов вызвать определит уже инфраструктура избавив нас от этой головной боли. В данном примере такой подход будет более удобен, т.к. у нас пропадет необходимость создавать куче if'ов по всему коду, что только упростит программу и сделает изменения более простыми.
Ну и опять же - все зависит от ситуации. Серебряной пули не бывает и в различных случаях стоит использовать различные подходы, которые будут более дешевы в каждой конкретной ситуации. Еще немного про ООП и остальное можете посмотреть в моей статье тут

Стоит ли заморачиваться с шаблонами проектирования?

На данный момент изучаю шаблоны проектирования и пробую применять их на практике, но из-за небольшого опыта работы с ними и отсутствия менторства в этом деле прошу у вас помощи.
Есть, например, задача - сделать стрипт для связи с людьми.
Подробней: Мы говорим что хотим связаться с пользователем определенным способом, задаем вспомогательную информацию для объекта, далее говорим отправить. В идеале вижу использование скрипта в виде с использованием фабрики и стратегии:
$object = Communication::GetDriver('sms'); $object->setMsg($text); $object->setTelephone($phone); $object->send();
Но может потребоваться отправить совершенно другим способом, например, в соцсеть.
$object = Communication::GetDriver('socialNetwork'); $object->setMsg($text); $object->setIdUser($id); $object->send();
Вот и вопрос, как лучше поступить? Стоит ли заморачиваться с шаблонами? Может быть, следует сделать все это отдельными классами? Это будет оправдано? При этом желательно ловить ошибки и вести лог происходящего.
А если использовать шаблоны то как объединить классы? Может быть, есть методы, как сделать лучше?


Ответ

Стоит. Только нужно внести ясность.
Обычно полагают, что код пишется "на один раз" или "код слишком простой". На практике часто оказывается, что "да, оно одноразовое, но надо добавить это...и это". В итоге рождается привычка сразу делать структурно - выделить классы, за которыми спрятать лапшу (точек расширения не надо, просто порядок), а в случае веба взять любой фреймворк, а не тешить себя мыслями "да тут делов то ерунда, роутинг простой, шаблоны не надо"
Практически всегда есть смысл разделить на логгеры, манагеры, ридеры, чтобы оперировать более высокими уровнями абстракции и спрятать за ними детали, если вы не пишете админские скрипты или не фрилансите (написал, отдал, забыл)
Главное не забывать, что шаблоны призваны решать общие проблемы общими способами. Поэтому не должно быть "ооп ради ооп" и "шаблоны ради шаблонов". Тут многие совершают ошибку - начитаются умных книг и пытаются применить шаблон.
Суть в том, что шаблоны - общие решения, которые как то названы. При решении проблем люди приходят к общим решениям, называют его и пишут в книжку. И шаблоны полезны - знание шаблонов может подсказать приемлемые варианты и мозг приучается видеть их сразу. Впрочем, даже если не знать ни одного, то на практике все равно сам их изобретаешь. Также помогают в коммуникации (назвать шаблон проще, чем пояснять, что за структура классов и как она связана). Но решать то нужно задачи, потому на задачах и нужно акцентироваться, а не на шаблонах.
Правильный путь такой: берем правило "делай все проще", добавляем в него "главная сила ооп не в 3 китах, а в гибкости объектов и возможности комбинировать их", приправляем приемами чистого кода и других парадигмами - и решаем задачу. Если видим, что подходит какой то шаблон (обычно не понять какой точно, слишком тонкая грань), то идем к нему решая задачу. Как только задача решена, то все - дальше реализовывать шаблон не нужно. Нет причины - нет кода. Неважно насколько решение получилось "классическим" - любое продолжение есть усложнение.
Так что разбираться в шаблонах полезно - это как перенимать чужой опыт решения типичных проблем. И использовать полезно. Но чтобы избежать попадания в ловушку "шаблоны ради шаблонов" следует использовать прием, каким шаблон решает задачу, закодить его и остановиться.

Верстка с учетом ppi устройств - как определять, каков подход?

Прошу прощения за картинки-сслыки (не хватает репутации) и за "много букав". О проблеме хочется хотя бы просто поговорить :)
Перелопатив с десяток статей я начал осознавать, что ppi - большая палка в колеса. Как с ним бороться, пока не ясно.
Итак, у нас есть элементарная страница: jsfiddle.net
Мы хотим 14px (к примеру) - как основной размер шрифта. Допустим, что так было в PSD от дизайнера. От этого будем отталкиваться.
Обварачиваем весь контент в div.font-size-setting, которому выставляем font-size: 1.4em (так как после нормализации у нас было 10px).
Смотрим на страницу с разных устройств:

Будь там iphone4 шрифт и квадратик были бы еще меньше. Проблема, очевидно, в большой разнице в ppi (pixels per inch) устройств. Обычные мониторы имеют 96ppi. У iphone3 163ppi. У виты 220ppi
Очевидное решение - это определить ppi устройства и увеличить шрифт. С последним проблем никаких. Обарачиваем в div.font-size-normalize и в зависимости от dpi выставляем соответствующий шрифт: jsfiddle.net
Получаем:
div.font-size-setting - чтобы выставить размер шрифта от дизайнера,
div.font-size-normalize - делаем этот шрифт одинакового размера (визуально) на всех устройствах.

Яблофон чуть растянул сам шрифт или увеличил расстояниями между строчкам, но по сути все сходится. Так или иначе, квадратик с размерами в em везде одинаковый, хоть линейкой меряй.
Вопрос в том, как определять ppi?
1.media queries - resolution Медиа запросы умеют определять не только ширину и высоту, но и много других характеристик, в том числе и dpi (dots per inch). Вообще dpi - бессмысленный параметр для дисплея, так как это параметр для печати принтером, но в нашем случае совпадает с ppi
Я решил, что не плохо было бы сделать шаг в 0.1em. Это примерно каждые 10ppi. Взяв наши 96ppi за 1em составил табличку и посчитал диапазон так, чтобы интересующие нас значения были в середине. Составил запросы:
@media screen and (min-resolution: 90dpi) and (max-resolution: 100dpi) { .font-size-normalize { font-size: 1em; /* normal desktops */ } } @media screen and (min-resolution: 101dpi) and (max-resolution: 111dpi) { .font-size-normalize { font-size: 1.1em; } } @media screen and (min-resolution: 112dpi) and (max-resolution: 122dpi) { .font-size-normalize { font-size: 1.2em; } } /*...*/ @media screen and (min-resolution: 158dpi) and (max-resolution: 168dpi) { .font-size-normalize { font-size: 1.7em; /* iphone3 */ } } /*...*/ @media screen and (min-resolution: 216dpi) and (max-resolution: 226dpi) { .font-size-normalize { font-size: 2.3em; /* ps vita */ } } /*...*/ @media screen and (min-resolution: 322dpi) and (max-resolution: 332dpi) { .font-size-normalize { font-size: 3.4em; /* iphone4 */ } }
http://jsfiddle.net/AHzYJ/3/
Последние версии десктопных браузеров проработали медиазапросы. Браузеры iphone3 и ps vita не осилили. Думаю последние яблофоны, яблопэды, дройдофоны все же справятся, но тем не менее решение далеко не пуленепробиваемо :(
2.media queries - devicePixelRatio и канонический пиксель dip - density(device)-independent pixel - что то вроде канонического пикселя. Равен одному физическому пикселю на 160ppi. С другой стороны мы имеем параметр devicePixelRatio, который может быть использован как аргумент медиа-запроса относительно канонического пикселя:
@media screen and (device-pixel-ratio: 1) {}
Можно написать аналогичное примеру выше множество запросов:
@media screen and (min-device-pixel-ratio: 1) and (max-device-pixel-ratio: 1.1) { .font-size-normalize { font-size: 2.3em; /* ps vita */ } }
Но у меня ни для одного девайса/компьютера/браузера этого толком сделать не получилось. Такое ощущение, что этот параметр может быть только целочисленным: единица - для iphone3, двойка - для iphone4. Более того, требуются вендерные префиксы, что уже как минимум говорит об отсутвии кросс-браузерности или кросс-девайсности. Еще одна несостыковка в том, что "device-pixel-ratio: 2" (означающий 320ppi) отрабатывает на iphone4, обладающий 326ppi
3.JS
alert(window.devicePixelRatio);
Думаю, оно работает точно так же как и второй способ. На iphone3 я увидел "1", так же как в десктопном браузере и на вите, что само собой чушь. На iphone4 высветилось "2", но после предыдущих фэйлов это уже не имеет значение. Еще проблема: тормозилла не справилась и показала undefined
4.Самописные JS-функции, определяющие ppi. Что-то типа взять device-width и поделить на width. Это работает на мобильных устройствах, так как нельзя сплющить окно браузера, но в десктопном браузере мы можем просто уменьшить размер окна и все сломается.
В конечном итоге, я не нашел ни одного полнофункционального решения. Думаю, что просто должно пройти время, пока "device-pixel-ratio: n" будет пониматься всеми. А пока надо придумать как максимизировать количество удачных определений ppi. Ведь описанные выше способы частично, но все же работают.
Кто что думает по этому поводу, какие можетe предложить решения и как можно обобщить вышеуказанные способы в один пусть полурабочий вариант?


Ответ

Спустя какое-то время я пришел к тому, что надо работать по второму предложенному мною способу. Суть рабты примерно следующая. Сайт верстается "как обычно", все размеры задаются в пикселях. Только теперь width: 100px не означает ширину в 100 физических пикселей дисплея. Это 100 некоторых абстрахных пикселей (device independent pixel). А дальше операционная система (или браузер) уже сами решают, как показать один такой абстрактный пиксель на дисплее. Помогает им в этом параметр devicePixelRatio. Если этот параметр равен единице, то абстрактный пиксель показывается один в один с физическим пикселем. Если равен двойке, то используется квадрат из четырех пикселей. Если мы возьмем случайный сайт, вообще не оптимизированный под дисплеи с высокой плотностью пикселя, то он никак не сожмется на ретине. Он будет выгялдеть как на обычном дисплее. Получается, что за размерами следить не нужно. Ширины, высоты, бордюры, тени и прочее можно задавать в обычных пикселях. И не беспокоится о том, что же там будет на ретине. А вот над графикой придется попотеть. Картинки на девайсах с высокой плостностью пикселя выглядят растянутыми. Их надо заменять на картинки увеличенные в соответствующее количество раз. Например. div { background: url(cake.png) no-repeat center top; }
@media screen and (-webkit-min-device-pixel-ratio: 2), screen and ( -moz-min-device-pixel-ratio: 2), screen and ( -o-min-device-pixel-ratio: 2), screen and ( min-device-pixel-ratio: 2) { div { background-image: url(cake@2x.png); background-size: 100%; // или вариации } }

Что такое stack trace, и как с его помощью находить ошибки при разработке приложений?

Иногда при запуске своего приложения я получаю подобную ошибку:
Exception in thread "main" java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Мне сказали, что это называется «трассировкой стека» или «stack trace». Что такое трассировка? Какую полезную информацию об ошибке в разрабатываемой программе она содержит?

Немного по существу: довольно часто я вижу вопросы, в которых начинающие разработчики, получая ошибку, просто берут трассировки стека и какой-либо случайный фрагмент кода без понимания, что собой представляет трассировка и как с ней работать. Данный вопрос предназначен специально для начинающих разработчиков, которым может понадобиться помощь в понимании ценности трассировки стека вызовов.
Перевод вопроса: «What is a stack trace, and how can I use it to debug my application errors?» @Rob Hruska


Ответ

Простыми словами, трассировка стека – это список методов, которые были вызваны до момента, когда в приложении произошло исключение.
Простой случай
В указанном примере мы можем точно определить, когда именно произошло исключение. Рассмотрим трассировку стека:
Exception in thread "main" java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Это пример очень простой трассировки. Если пойти по списку строк вида «at…» с самого начала, мы можем понять, где произошла ошибка. Мы смотрим на верхний вызов функции. В нашем случае, это:
at com.example.myproject.Book.getTitle(Book.java:16)
Для отладки этого фрагмента открываем Book.java и смотрим, что находится на строке 16
public String getTitle() { System.out.println(title.toString()); <-- line 16 return title; }
Это означает то, что в приведенном фрагменте кода какая-то переменная (вероятно, title) имеет значение null
Пример цепочки исключений
Иногда приложения перехватывают исключение и выбрасывают его в виде другого исключения. Обычно это выглядит так:
try { .... } catch (NullPointerException e) { throw new IllegalStateException("A book has a null property", e) }
Трассировка в этом случае может иметь следующий вид:
Exception in thread "main" java.lang.IllegalStateException: A book has a null property at com.example.myproject.Author.getBookIds(Author.java:38) at com.example.myproject.Bootstrap.main(Bootstrap.java:14) Caused by: java.lang.NullPointerException at com.example.myproject.Book.getId(Book.java:22) at com.example.myproject.Author.getBookIds(Author.java:35) ... 1 more
В этом случае разница состоит в атрибуте "Caused by" («Чем вызвано»). Иногда исключения могут иметь несколько секций "Caused by". Обычно необходимо найти исходную причину, которой оказывается в самой последней (нижней) секции "Caused by" трассировки. В нашем случае, это:
Caused by: java.lang.NullPointerException <-- root cause at com.example.myproject.Book.getId(Book.java:22) <-- important line
Аналогично, при подобном исключении необходимо обратиться к строке 22 книги Book.java, чтобы узнать, что вызвало данное исключение – NullPointerException
Еще один пугающий пример с библиотечным кодом
Как правило, трассировка имеет гораздо более сложный вид, чем в рассмотренных выше случаях. Приведу пример (длинная трассировка, демонстрирующая несколько уровней цепочек исключений):
javax.servlet.ServletException: Произошло что–то ужасное at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at org.mortbay.jetty.Server.handle(Server.java:326) at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943) at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756) at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228) at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) Caused by: com.example.myproject.MyProjectServletException at com.example.myproject.MyServlet.doPost(MyServlet.java:169) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30) ... 27 more Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822) at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689) at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344) at $Proxy19.save(Unknown Source) at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below) at com.example.myproject.MyServlet.doPost(MyServlet.java:164) ... 32 more Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...] at org.hsqldb.jdbc.Util.throwError(Unknown Source) at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source) at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105) at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57) ... 54 more
В этом примере приведен далеко не полный стек вызовов. Что вызывает здесь наибольший интерес, так это поиск функций из нашего кода – из пакета com.example.myproject. В предыдущем примере мы сначала хотели отыскать «первопричину», а именно:
Caused by: java.sql.SQLException
Однако все вызовы методов в данном случае относятся к библиотечному коду. Поэтому мы перейдем к предыдущей секции «Caused by» и найдем первый вызов метода из нашего кода, а именно:
at com.example.myproject.MyEntityService.save(MyEntityService.java:59)
Аналогично предыдущим примерам, необходимо обратить внимание на MyEntityService.java, строка 59: именно здесь появилась ошибка (в данном случае ситуация довольно очевидная, так как об ошибке сообщает SQLException, но в этом вопросе мы рассматриваем именно процедуру отладки с помощью трассировки).
Перевод ответа: «What is a stack trace, and how can I use it to debug my application errors?» @Rob Hruska

Фрагментация памяти

Как известно, сборщик мусора в C# (точнее, в CLR) время от времени проводит чистку оперативной памяти, освобождая память, занятую переменными, которые больше не используются. Кроме этого он также производит дефрагментацию памяти, "уплотняя" кучу.
В связи с этим происходит коррекция ссылок на объекты, пережившие сборку мусора. Вероятно, что-то аналогичное происходит при сборке мусора и в других языках.
В С++ нет сборщика мусора. В таком случае, даже если программист не забудет очистить всю память, выделенную ранее, то ее все равно может оказаться недостаточно из-за фрагментации, так как процесс дефрагментации не проводится.
То есть возможна парадоксальная ситуация, когда общий размер свободной памяти больше, чем требуется для создания нового объекта, но объект не может быть создан. Так ли это? Есть ощущение, что я ошибаюсь в своих рассуждениях, но где?


Ответ

Вопрос очень хороший. И тема интересная и важная. Однако, мне кажется (может быть, просто кажется), что Вы путаете две вещи, точнее, два уровня фрагментации памяти. Память может быть фрагментирована на уровне физической памяти. В системах с виртуальной моделью памяти (а таких сейчас подавляющее большинство) это не проблема, так как даже сильно фрагментированная реальная память будет просто спроецирована на последовательное виртуальное адресное пространство процесса. Другое дело, если фрагментация происходит на уровне виртуальной памяти. Это может запросто произойти в программах на С или С++, где происходит многочисленные выделения и удаления небольших фрагментов памяти. Это может привести к сильной утечки памяти (хотя в коде вся выделенная память освобождается!) и, возможно, к исчерпанию всей системной памяти. Но тут уже всему настанет кердык, если система такие ситуации не отслеживает и не выгружает "прожорливые" процессы.

Как писать простейшие UnitTest'ы к простейшим функциям?

Хочу научиться писать тесты для своих проектов.
Подскажите какие-нибудь хорошие ресурсы, чтобы научиться тестировать Android приложения.
Насколько важно их использование?
Сейчас я пишу приложение без их использования и пока не могу оценить их пользу.
Те коды, которые встречаю в интернете, не помню, чтобы где-то в коде встречал тесты.
В общем, хочу понять, что это значит. Подскажите, с чего начать.
Допустим есть вот такой метод:
private File getFile(File path) { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); return new File(path.getPath() + File.separator + timeStamp + ".html"); }
Как можно к нему написать тест и что нужно для этого сделать?
ПРАВКА
Вот кстати есть ссылка с видео где показан пример теста
https://www.youtube.com/watch?v=ZJE0MDKJOow


Ответ

Для того чтобы создать юнит тест, вам прежде всего нужно определиться что вы собственно собираетесь тестировать. В идеале, ваш метод должен делать что-то одно и тогда ваша задача упрощается. Если возможно, то юнит тест должен тестировать метод как черный ящик, то есть, вы подаете что-то на вход и проверяете полученное значение. К сожалению это не всегда возможно.
В вашем конкретном случае, первое что бросается в глаза, это то что метод помечен как private, такой метод нельзя тестировать стандартными методами. Существует много теорий насчет того нужно ли тестировать приватные методы или нет. Мое мнение - их можно не тестировать. Правильность работы приватных методов будет проверена неявно когда вы тестируете все открытые методы. Хотя если вы очень хотите то можно пометить метод как 'default' (убрать тип доступa), или можно использовать reflection.
Но допустим ваш метод публичный, тогда анализируя код понимаем, что метод возвращает новый файл с именем построенным из пути и функции текущей даты. То есть, он делает два действия: * Создает имя файла * Создает собственно файл Тестировать его в текущем виде можно но не интересно. Я бы посоветовал немного поправить ваш код чтобы он был более пригодным для тестирования:
public File getFileFullName(File path, Date date) { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String fullPath = path.getPath() + File.separator + timeStamp + ".html"; return fullPath; }
// где-то в вашем коде String path = ... Date now = new Date(); String fileFullName = getFileFullName(path, now); File file = new File(fileFullName);
// тест для метода getFileFullName в классе ClassUnderTest @Test public void testGetFileFullName() { String path = "/abc"; Date date = new Date(1465953124); //2016-06-15 13:12:06
ClassUnderTest instance = new ClassUnderTest() String name = instance.getFileFullName(path, date);
assertEquals("/abc/20160615_131206.html"); }
Но вы можете спросить, а как тестировать код где мы создаем дату или используем файл? Касательно даты, я бы рекомендовал вообще не использовать new Date() в коде. Вместо этого использовать что типа провайдера или сервиса для получения текущей даты/времени. Тогда вы можете подменять реализацию этого класса для тестирования. Простейшая реализация может быть синглтон:
public class DateTimeUtils {
private static DateTime fixedTime;
public static DateTime getCurrentDateTime() { if (fixedTime == null) { return new DateTime(DateTimeZone.UTC); } return fixedTime; } public static void useFixedCurrentTime(DateTime timeToReturn) { fixedTime = timeToReturn; } }
Что касается объекта File то здесь вам поможет подмена классов с помощью мокирования. Посмотрите Mockito или PowerMock.
Еще маленькое дополнение. Если бы вы использовали test-driven development то такой проблемы бы не было.

Что такое interning и как им пользоваться

Что такое interning? Для чего оно применяется? Когда стоит его применять и какие возможны подводные камни?


Ответ

Interning — это метод хранения лишь одной копии из многих одинаковых объектов. Применяется в C# и Java к строкам, а также (в Java) к небольшим числам.
Рассмотрим на примере строк. Когда вы говорите string.Intern(s) в C# или s.intern() в Java для строки s, вы получаете строку с таким же содержимым, но возвращённая строка гарантировано одна и та же (то есть, один и тот же объект), если вы запрашиваете интернированную строку с одним и тем же содержимым. Также, строковые константы автоматически интернируются.
Однако, строки полученные другим путём, например, через StringBuilder или конкатенацию, не будут интернированы, по крайней мере в текущей версии языков. (Впрочем, оптимизатор может соптимизировать конкатенацию, если сумеет вычислить аргументы во время компиляции, так что рассчитывать на это не стоит.)
Пример:
// C# object.ReferenceEquals("123", "123") // true object.ReferenceEquals(string.Intern("12" + "3"), "123") // true char[] chars = new[] { '1', '2', '3' }; object.ReferenceEquals(new string(chars), new string(chars)) // false object.ReferenceEquals(new string(chars), "123") // false object.ReferenceEquals(string.Intern(new string(chars)), "123") // true
// Java "123" == "123" // true ("12" + "3").intern() == "123" // true new String("123") == new String("123") // false new String("123") == "123" // false new String("123").intern() == "123" // true
Это значит, что интернированные объекты можно сравнивать через ReferenceEquals (C#) / == (Java).
Когда вызывается метод Intern()/intern(), рантайм-библиотека просматривает пул интернированных объектов в поисках данного или равного ему. Если такой объект находится, он возвращается, если нет, данный объект интернируется и возвращается.

Для чего можно пользоваться этим? Например, можно уменьшить расход памяти программы, если в ней используется большое количество строк, среди которых много дубликатов. Например, у вас есть огромный XML-файл, состоящий из почти одинаковых записей. Или огромный текст программы на каком-нибудь языке программирования. Тогда в некоторых случаях можно уменьшить потребление памяти путём интернирования строк: например, все экземпляры while будут одним и тем же объектом.
Внимание! Сама по себе считанная из файла строка не интернируется, даже если она и равна какой-то интернированной строке.
Учтите, однако, что однажды интернированую строку нельзя «деинтернировать», и она будет занимать память программы даже когда больше не будет вам нужна. Поэтому имейте в виду, что интернирование строк может оказать и негативный эффект на расход памяти программой!
Поэтому если вы решаете применить интернирование в своей программе, обязательно спрофилируйте расход памяти и убедитесь, что ваша оптимизация действительно улучшает ситуацию! (Впрочем, это относится практически ко всем оптимизациям.)
Далее, интернирование строки делает поиск в глобальных структурах, и поэтому наверняка будет требовать глобальной блокировки. Поэтому несколько потоков, активно применяющих интернирование, будут «сражаться» за общий ресурс.
Ещё одним преимуществом интернированных строк является то, что их можно быстрее сравнивать. Например, если вы разбираете программный текст, и все ключевые слова интернированы, вы можете сравнивать их как объекты (что, разумеется, намного скорее).

В .NET вы можете управлять тем, будет ли применяться автоматическое интернирование строковых констант на уровне сборок (assembly). По умолчанию строковые константы, как было сказано выше, интернируются, но вы можете запретить это, указав атрибут CompilationRelaxations.NoStringInterning

В Java кроме строк интернируются также и упакованные (boxed) числа. Например, упакованные константы типов Integer и Long в пределах от -128 до 127, Boolean и Byte хранятся в пуле интернированных объектов. Пример:
Integer x = 1; Integer y = 1; Integer z = new Integer(1);
x == y // true y == z // false

Почему во многих примерах функции называют foo?

Часто вижу в различной литературе, видеоуроках, статьях в интернете и прочем, что демонстративные функции и методы носят название foo. Что это значит ?


Ответ

Скорее всего слова foo, bar и baz родились в комиксе Smokey Stover and Pogo в конце 30-х годов 20-го века (как правильно заметил AnT) и, благодаря своей популярности, стали использоваться технарями из MIT
От автора комикса
What’s Foo? My uncle found this word engraved on the bottom of a jade statue in San Francisco’s China town. The word Foo means Good-Luck. Что такое Foo? Мой дядя нашел это слово выгравированным на дне нефритовой статуэтки в «China town» в Сан Франциско. И обозначает (переводится) оно «удача» или «удачи!»
Вот очень подробный и развернутый ответ на этот вопрос в английской версии StackOverflow. В этом ответе есть воспоминания людей об употреблении слов foobarbazfoobar , которые работали непосредственно в Tech Model Railroad Club (сокращенно TRMC) или, несколько позже, просто в кругу MIT в 1960-1990-х годах.
Также в популяризации данных слов сыграла роль военная аббревиатура FUBAR («Fucked Up Beyond All Repair», что можно перевести как «ремонту не подлежит», что относилось к военной технике, либо «Fucked Up Beyond All Recognition» — речь шла о людских жертвах, которые невозможно опознать), которая появилась во время второй мировой войны и по слухам была придумана неким рядовым, которого «задолбали» всякие военные аббревиатуры.
Технари из TRMC клуба в MIT использовали слово «FOO» для обозначения ситуаций когда была необходима аварийная остановка системы. В случае, когда кто-нибудь нажимал один из аварийных выключателей на системном табло вместо времени появлялась надпись «FOO» и поэтому эти выключатели назвали «Foo switches». Позже в этом клубе стали использовать кнопки с подписями «FOO» и «BAR» (уже как дань традиции), и использовались они в самых разных ситуациях.
Впоследствии это стало использоваться в IT мире как «placeholders», то есть для названия переменных/классов в тех случаях, когда это не важно (например в примерах) или когда на ум ничего лучшего не приходит.
P.S.: также существует неподтвержденная версия, что «FOOBAR» происходит от немецкого «furchtbar» (ужасно).