Pull to refresh
4
0
Артём Борисовский @burjui

Программист

Send message
В этой ветке до вашего появления никто и не слыхал о вашей проблеме, и, уж тем более, не предлагал вариантов её решения. Мы тут об изотопах углерода говорим, сложность большинства соединений которого значительно выше сложности ваших сплавов. Речь идёт о различиях не уровня металл/галоген, а о таких, которые лишь слегка меняют пространственную структуру молекулы, что оказывается достаточным для нарушения хрупкого баланса в обмене веществ живого организма. Впрочем, эти вещи не нужно объяснять такому опытному специалисту, как вы.
Именно. Атомы большей массы обладают большей инерцией, соответственно реагируют медленнее, а также влияют на структуру связей из-за смещения центров масс в молекулах. Чем больше минимальная масса атома, тем меньше различия в химических свойствах, так что разницы между изотопами урана вы не заметите, но вот между изотопами водорода — запросто: например, тяжёлая вода (D20) губительна для живых организмов из-за того, что дейтерий нарушает молекулярную структуру белков и прочих сложных органических соединений.

А вообще, химия как свойство материи строится на физических законах, а там много переменных, которые нужно учитывать. Соответственно, химия как наука обычно изучает приближённые модели.
Однако тем выше вероятность, что на новом месте работы вам придётся разгребать авгиевы или чьи-то ещё конюшни кода.
Эта «прихоть» продиктована чисто практическими соображениями. В проекте такой сложности и с такими требованиями к надёжности, как в Linux, C++ будет как скальпель с атомной батарейкой, оптическим прицелом и тепловым автонаведением: всё это можно отключить, но пульт от скальпеля есть даже у уборщицы, и никто не застрахован от внезапной кровавой бани.
По мне, так имена несут основную смысловую нагрузку в коде, а типы — это скорее инструменты. Вы можете сделать стул из дерева или из алюминия, но главным будет всё-таки назначение предмета, а не материалы, из которых он сделан. В данной аналогии стул — это имя сущности, а дерево и алюминий — типы (скажем, Int и Double).

Вот вам наглядный пример в коде:
import A.B
import A.C

sealed class A<T> {
    class B<T>(val c: A<T>, val d: A<T>): A<T>() {
        override fun toString(): String = "($c $d)"
    }
    
    class C<T>(val e: T): A<T>() {
        override fun toString(): String = "$e"
    }
}

fun main(args: Array<String>) {
    val f = B(C(1), B(C(2), C(3)))
    println("$f")
}

Очевидно, не правда ли? Куда проще, чем:
import BinaryTree.Node
import BinaryTree.Leaf

sealed class BinaryTree<T> {
    class Node<T>(val left: BinaryTree<T>, val right: BinaryTree<T>): BinaryTree<T>() {
        override fun toString(): String = "($left $right)"
    }
    
    class Leaf<T>(val value: T): BinaryTree<T>() {
        override fun toString(): String = "$value"
    }
}

fun main(args: Array<String>) {
    val tree = Node(Leaf(1), Node(Leaf(2), Leaf(3)))
    println("$tree")
}
Равно как и с Kotlin. Так что можно про J&J зыбыть на год-другой.
Всё верно. Я неоднократно обращал внимание на то, что многие бизнесмены успешны не потому, что всегда принимают верные решения, а потому, что не бояться риска. Это то, чего многим из нас не хватает, потому что отбито с детства.
Разумеется, математика полезна, но какой смысл программисту плотно забивать голову всякими кольцами и интегралами, если это делается в отрыве от практики? Сначала ты два года просто изучаешь матан одновременно с программированием, но безо всякой связи, а потом чудесным образом должен догадаться, в чём эта связь заключается. Но если нет связи, то кажется, что это не нужно — вот и пропадает мотивация, а без мотивации знания в голову не залезут, и толку от «учиться получать знания» — ноль. Так можно не знания получить, а зазубрить материал и благополучно его забыть. И да, больше всего будет именно матана, а не алгебры, логики и дискретки, из которых программирование и выросло, вообще-то. Лямбда-исчисление? Нет, зачем, лучше порешай дифуры.

В комментах многие выгораживают преподавателей ВУЗов — дескать, это не их задача прививать интерес. Но это их профессия — педагогика, вообще-то. Или профессиональные педагоги не в курсе, что интерес к предмету — залог его глубокого понимания? Ну, тогда я тоже могу сказать, что продумывать архитектуру и писать красивый код я не обязан: мол, зачем мне стараться, если говнокод на глобальных переменных уже написан и работает? Такой же дубовый подход.

Мне лично из ВУЗовской программы в профессии не пригодилось практически ничего. Кое-какие полезные вещи там были, но они утонули в том диком объёме знаний, который больше пригодился бы физику, нежели разработчику ПО. И теперь области математики, имеющие отношение к программированию, я изучаю самостоятельно — и всё гораздо понятнее, когда уже умеешь программировать, и видишь связь этих областей с практикой. Ну, а небольшая книга Эдварда Френкеля «Любовь и математика» дала мне больший заряд мотивации изучать математику, чем все годы учёбы.
Доля правды в этом есть. Впрочем, я для себя решил: код, который не критичен для моей текущей задачи, но важен с точки зрения архитектуры или красоты кода, я всё равно напишу, кто бы что ни говорил. Время покажет, кто был прав — я со своим «перфекционизмом» или начальник с противоположным настроем («как только код работает — приступаешь к следующей задаче»). Обычно всё проходит более-менее гладко: выкидывается старый говнокод (в том числе мой, ибо я далеко не гений), пишется новый, лучший, с меньшим количеством багов. Бывает, я оказываюсь неправ, и просто трачу время зря (скользкая тема: вроде бы ничего не сделал, но опыт-то появился). Но мне кажется, лучше проверить, набить шишку и идти дальше с новым знанием — «так делать плохо», чем только идти на поводу, словно робот, и никогда не экспериментировать, не проявлять инициативу. В конце концов, если встанет вопрос моей несовместимости с текущим местом работы, я могу тщательно проанализировать ситуацию и решить, что лучше — менять себя или найти другое место.

От прокрастинации время от времени страдаю, но начал замечать, что чем больше я переживаю по этому поводу, тем больше прокрастинирую. Думаю, здесь работает механизм, похожий на работу наркотиков: когда ты себя плохо чувствуешь, возникает нужда в приятных ощущениях, и прокрастинация их даёт, при этом по прошествии очередного «приступа» ты понимаешь, что не сделал ничего полезного, и снова чувствуешь себя плохо. Разумеется, оценка прокрастинации окружающими заметно влияет на её закрепление в психике: если тебя постоянно только ругают за нерешённые вовремя задачи, это ничуть не прибавляет энтузиазма, только ухудшая настроение, и в итоге получается замкнутый круг. Опять же, прослеживается аналогия с наркотиками (в т.ч. алкоголем и никотином): психика больного слишком слаба, чтобы противиться искушению, а слепое порицание окружающих и постоянные напоминания о том, какая ты тряпка, делают её ещё слабее.

В общем, часто эгоизм и безразличие окружающих только подпитывают пороки: большинство людей мало волнуют твои настоящие проблемы, им лень разбираться в тебе, пытаться тебя понять, им лишь нужно, чтобы ты соответствовал их критериям «приличного» человека. Как говориться, «моя хата — с краю». И тут всё уже зависит от тебя — будешь ли ты молча соглашаться с тем, что ты тряпка, и страдать от этого, или же скажешь себе, что всё не так плохо, что ты просто запутался, и начнёшь искать настоящие причины проблемы.

Резюме.
Часто окружающим пофиг на твои проблемы, они видят в тебе тряпку и постоянно об этом напоминают. Но необходимо усвоить одну важнуюм ысль: совершать ошибки — это нормально, покуда извлекаешь из них уроки. К этой мысли нужно привыкнуть, и тогда страх начнёт исчезать, ты перестанешь бояться накосячить и будешь спокойно браться за проблему. Самое страшное, что может случиться — не успеешь или сделаешь плохо, и тебе об этом скажут. Ну, или не получишь премию. В конце концов, живёшь только один раз — так зачем лишать себя возможности проявить инициативу и быть честным с самим собой, если это не принесёт тебе счастья?

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

Немного специфического чёрного юмора по теме (18+):
www.youtube.com/watch?v=cSD75sKkB0U
www.youtube.com/watch?v=6LESiu3OFLQ
Я в курсе, но в D const int* x по умолчанию не даёт выстрелить в ногу, а C++ вариант const int* const x выглядит уже не так опрятно. В C++ вообще много чего есть, но есть языки, в которых это сделано лучше.
Может, и так, но «const-нацизм» используется в первую очередь для того, чтобы оградить себя от случайной модификации данных (будь то аргументы или локальные переменные), и уже во вторую очередь — для оптимизации. D C++ это работает так себе, поэтому в D пошли ещё дальше, и сделали const транзитивным:
void fn(const int *x)
{
    int y;
    x = &y; // error
    *x = y; // error
}

Вот так в D объявляется изменяемый указатель на неизменяемый int:
const(int) *x

Если указатель константный, то и данные, доступные через него — тоже. Вот это настоящий const-нацизм.
А, мне кажется, это связано с меньшим количеством падежей и гораздо меньшим их использованием в английском языке. В русском языке ситуация иная: во-первых, «я» склоняется по падежам (+ меня, мне, мной; в английском только + me), а во-вторых, местоимения часто можно опускать, т.к. их с успехом заменяют суффиксы глаголов (работаю, работаешь и т.п.).
Справедливости ради, библиотеку можно использовать и с AVR — нужно только драйвер пинов написать (мне было не до этого, поэтому AVR в комплект не входит), памяти нужно байт 100, к тому же библиотека на чистом C. ATtiny — понятное дело, хардкор, туда вообще ничего не впихнёшь без напильника и вазелина, единственный плюс — размер.
Когда-то давно я портировал Arduino-библиотеку LCD на чистый C, попутно сделав её кросс-платформенной:
https://github.com/RoboCraft/HD44780

Ввод-вывод в ней абстрагирован в драйверы через такую структуру:

struct HD44780_GPIO_Interface_Struct;
typedef struct HD44780_GPIO_Interface_Struct HD44780_GPIO_Interface;

struct HD44780_GPIO_Interface_Struct
{
  HD44780_Result (*configure)(HD44780_GPIO_Interface *interface, HD44780_Pin pin, HD44780_PinMode mode);
  HD44780_Result (*write)(HD44780_GPIO_Interface *interface, HD44780_Pin pin, HD44780_PinState value);
  HD44780_Result (*read)(HD44780_GPIO_Interface *interface, HD44780_Pin pin, HD44780_PinState *value);
};

Этакий C++ интерфейс для бедных: заполняем структуру указателями на функции управления пинами и отдаём библиотеке, а она уже работает с пинами через эти указатели. В папке drivers/ лежат реализации для STM32, в examples/ есть примеры использования. Они могут показаться громоздкими, но это издержки C и плата за гибкость: можно управлять экраном хоть через сдвиговый регистр, хоть по радио — нужен только драйвер пинов, порядок пинов вы задаёте сами при инициализации библиотеки.

Пример для STM32F10x
HD44780_STM32F10x_GPIO_Driver lcd_pindriver;

void init_lcd(void)
{
  /* Распиновка дисплея */
  const HD44780_STM32F10x_Pinout lcd_pinout =
  {
    {
      /* RS        */  { GPIOA, GPIO_Pin_6 },
      /* ENABLE    */  { GPIOA, GPIO_Pin_5 },
      /* RW        */  { GPIOA, GPIO_Pin_4 },
      /* Backlight */  { NULL, 0 },
      /* DP0       */  { NULL, 0 },
      /* DP1       */  { NULL, 0 },
      /* DP2       */  { NULL, 0 },
      /* DP3       */  { NULL, 0 },
      /* DP4       */  { GPIOA, GPIO_Pin_3 },
      /* DP5       */  { GPIOA, GPIO_Pin_2 },
      /* DP6       */  { GPIOA, GPIO_Pin_1 },
      /* DP7       */  { GPIOA, GPIO_Pin_0 },
    }
  };

  /* Настраиваем драйвер: указываем интерфейс драйвера (стандартный),
     указанную выше распиновку и обработчик ошибок GPIO (необязателен). */
  lcd_pindriver.interface = HD44780_STM32F10X_PINDRIVER_INTERFACE;
  /* Если вдруг захотите сами вручную настраивать GPIO для дисплея
     (зачем бы вдруг), напишите здесь ещё (библиотека учтёт это):
  lcd_pindriver.interface.configure = NULL; */
  lcd_pindriver.pinout = lcd_pinout;
  lcd_pindriver.assert_failure_handler = hd44780_assert_failure_handler;

  /* И, наконец, создаём конфигурацию дисплея: указываем наш драйвер,
     функцию задержки, обработчик ошибок дисплея (необязателен) и опции.
     На данный момент доступны две опции - использовать или нет
     вывод RW дисплея (в последнем случае его нужно прижать к GND),
     и то же для управления подсветкой. */
  const HD44780_Config lcd_config =
  {
    (HD44780_GPIO_Interface*)&lcd_pindriver,
    delay_microseconds,
    hd44780_assert_failure_handler,
    HD44780_OPT_USE_RW
  };

  /* Ну, а теперь всё стандартно: подаём тактирование на GPIO,
     инициализируем дисплей: 16x2, 4-битный интерфейс, символы 5x8 точек. */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  hd44780_init(&lcd, HD44780_MODE_4BIT, &lcd_config, 16, 2, HD44780_CHARSIZE_5x8);
}


Об этой библиотеке есть статья:
http://robocraft.ru/blog/algorithm/785.html

Всё это уже успело порости мхом (2012 г.), и к библиотеке я с того времени не прикасался (драйвер для Arduino придётся писать вам) но вдруг кому пригодится.
Если точнее, то именно поддержки вовсе нет — есть возможность. Что ни возьми — Go, C++ или Pascal — всё равно всё придётся делать через JNI, т.к. подавляющая часть Android API написана на Java и недоступна напрямую в native code, так что полноценное приложение нельзя написать целиком даже на C++, на котором сам Android написан. Другими словами, в Android внутри C++, а снаружи — Java. А для полноценной поддержки нужен C'шный API, для работы с которым уже сто лет в обед существуют всевозможные FFI в подавляющем большинстве языков программирования.
Не считая дикого насилия над кэшем и отсутствия нормального prefetch при итерации по LL.
Это, пожалуй, самый важный момент. К тому же, если блок памяти целиком помещается в cache line, это полностью устраняет задержки на чтение RAM, поэтому экономить память и держать данные близко друг к другу очень важно для обеспечения максимальной производительности. Хотя JVM/Dalvik вряд ли дадут выжать из процессора все соки.
К сожалению, документации по этой библиотеке кот наплакал, так что приходится копать исходники: https://github.com/bodar/totallylazy/blob/master/src/com/googlecode/totallylazy/Sequence.java
Просто сравните, какие методы есть у Sequence, и какие — у Stream. Мне, например, недавно пригодились groupBy и zip. К тому же, totallylazy — библиотека для ФП, так что кроме Sequence, там есть Either и Option, которые тоже умеют map/flatMap, а также всякие монады с функторами, предикаты и их модификаторы, да куча всего. Почти все методы доступны для статического импорта. Пример из приложения для Android:

final int color = option(json.optString("some_color", null))
    .filter(not(String::empty))
    .flatMap(Color::parseColor)
    .getOrElse(Color.WHITE);
view.setBackgroundColor(color);
Во избежание недопонимания: я только предлагаю использовать Iterable для аргументов, когда не нужна возможность менять последовательность — но и тогда лучше принимать базовые типы вроде Collection и List. Я не призываю возвращать Iterable из функций, тем более что это не нужно, т.к. любая коллекция реализует этот интерфейс, и не вызванному методу решать, как возвращаемая коллекция будет использоваться дальше (если, конечно, речь не идёт о каком-либо API).
Процитирую сам себя:
если, конечно, не нужен какой-нибудь специфичный для класса коллекции метод
size() сюда же. Разумеется, Iterable не подходит для случаев, когда вы нужно знать точное количество элементов. Впрочем, это зависит от задачи.

Вы не сможете работать с большим количеством полезных функций из Collections (guava несколько исправляет эту проблему, но тем не менее)
Вы не сможете легко и просто создать stream в Java 8
Согласен. Впрочем, зато я легко смогу использовать totallylazy, которая функционально (нечаянный каламбур) гораздо богаче Stream из Java 8, частично заменяет Collections и доступна на Android (с Retrolambda идёт на ура).

В целом, я бы крайне осторожно использовал бы замену Collection на Iterable в больших функциях, чтобы не пришлось рефакторить пол приложения, когда потребуется Collection или не делать костыли и терять производительность.
Заменять и не надо. Просто пишите новые алгоритмы, исходя из принципа минимализма: нужна последовательность — принимай Iterable, понадобится менять последовательность — меняешь на Collection (не надо переписывать половину кода для этого).

Information

Rating
Does not participate
Location
Калининград (Кенигсберг), Калининградская обл., Россия
Date of birth
Registered
Activity