VLIW это не конкретная архитектура типа x86/ARM/MIPS, это скорее "стиль" набора команд. По уровню абстракции это на уровне с CISC и RISC. Например, недавно официально почивший Itanium это тоже VLIW.
Насчёт пункта 2 — тут вполне логично всё. Если мы используем wildcard, то мы явно заявляем компилятору, что мы не знаем соответствующий тип. ? до некоторой степени эквивалентен ? extends Object, что делает Ref<?> ковариантным; следовательно, методы, которые принимают значение типа-параметра в качестве аргумента вызывать больше нельзя. В противном случае в компиляторе должен быть механизм отслеживания того, откуда какое значение пришло, что в общем случае мне кажется эквивалентным проблеме останова.
Насчёт 3 пункта мне тоже не кажется наличие проблемы очевидной. В конце концов, вы там мешаете дженерики и сырые типы, чего делать очень не рекомендуется. Решение, как вы заметили — не использовать сырые типы. Про сырые типы лучше вообще забыть в аспекте написания кода, это страшенный костыль для обратной совместимости.
Первое это вообще треш, да. Никогда правда с таким не сталкивался.
А для рисования используется AWT, да. Что-то производительное и сложное на этом написать трудно, Graphics и Graphics2D в первую очередь сделаны для рисования кастомных виджетов, не для сложных двигающихся изображений.
Интересно, что в Future'ах скалы это проблема решается тем, что все методы, которые принимают коллбэки, также принимают параметром executor, в котором коллбэк должен выполниться, поэтому всегда можно указать нужный executor и сериализовать обращения к мутабельному состоянию. Хотя для этого лучше конечно использовать библиотеки вроде Akka.
Типы, которые вы написали, не эквивалентны. Первое — это тип второго порядка, т.е. с сигнатурой * -> *. Второе — это конкретный (первого порядка) экзистенциальный тип, т.е. с сигнатурой просто *. Грубо говоря, первый тип вы можете применить к какому-то типу и получить новый тип, второй же применять не к чему, он уже конкретный, хоть и экзистенциальный. Вот этот плагин к компилятору: https://github.com/non/kind-projector позволяет записывать такие типы удобнее.
Пожалуйста, не нужно продолжать использовать эту древнюю тулзовину. Есть гораздо более адекватные современности вещи; если хочется лёгкой императивности, то можно взят тот же Gradle.
Брр, как вспоминаю рекурсивные антовые сборки из сотен файлов по несколько тысяч строк...
Пусть площадь диафрагмы фиксированная, и общая площадь матрицы тоже фиксированная. Тогда если за диафрагмой матрица с "большими" ячейками, на каждую ячейку в отдельности попадёт больше света, чем если за ней будет матрица с "маленькими" ячейками. Если на каждую ячейку попадает больше света, снимок становится в целом ярче. Здесь важен не размер матрицы в целом, а размер отдельного светочувствительного элемента.
Хочу сказать, что ставить GraphStage на один уровень с Sink и Source — это примерно как говорить, что у нас есть Map, Set и LinkedList. Утверждение корректное, но Sink и Source — это интерфейсы, обозначающие конец и начало стрима, а GraphStage — это конкретная реализация стримов произвольной формы (GraphStage может иметь форму Sink'ов, Source'ов, Flow'ов, BidiFlow'ов и прочего).
Основные интерфейсы в Akka Streams это Source, Flow и Sink:
Linear processing pipelines can be expressed in Akka Streams using the following core abstractions:
Source: A processing stage with exactly one output, emitting data elements whenever downstream processing stages are ready to receive them.
Sink: A processing stage with exactly one input, requesting and accepting data elements possibly slowing down the upstream producer of elements
Flow: A processing stage which has exactly one input and output, which connects its up- and downstreams by transforming the data elements flowing through it.
RunnableGraph: A Flow that has both ends "attached" to a Source and Sink respectively, and is ready to be run().
GraphStage же позволяет реализовать на низком уровне произвольную логику части стрима с произвольным количеством входов и выходов. Это очень мощная штука, но ей довольно сложно пользоваться, и, как правило, она нужна для реализации абстрактных примитивов, которые потом переиспользуются, а не для непосредственно бизнес-логики приложения. Для бизнес-логики гораздо удобнее и проще использовать акторов.
А почему owncloud а не nextcloud? Насколько я помню, в nextcloud ушла большая часть разработчиков owncloud, и сам он позиционируется как более свободная альтернатива.
"Механизм эволюции" — это ярлык, краткая ссылка на конкретный набор физических процессов, которые мы можем либо наблюдать, либо экстраполировать исходя из наблюдений. Поэтому некорректно спрашивать "когда был создан механизм эволюции". Он был "создан", если хотите, когда какой-то учёный, понаблюдав за природой, обнаружил некоторые закономерности и назвал их "эволюцией".
Всё то же самое относится и к критериям отбора. Они ниоткуда не возникли, потому что они не являются какой-то отдельной сущностью, как скажем камень или озеро. "Критерии отбора в механизме эволюции" это всего лишь символ, которым мы пользуемся для описания условий, при которых работает "механизм эволюции", который, в свою очередь, является краткой ссылкой на описание конкретных физических процессов, которые мы можем наблюдать.
Следовательно, некорректно уравнивать "механизм эволюции" и "бога" с точки зрения "веры" в них, потому что "механизм эволюции" определяется через физические процессы, которые мы можем непосредственно наблюдать и даже ставить эксперименты (т.е. он основан на свойствах объективной реальности), а в "бога" можно только "верить".
И заметьте, что вопрос о том, почему существуют именно такие физические процессы, которые составляют "механизм эволюции", и откуда они взялись — это совершенно другой вопрос, и совершенно другая область знания. Теория эволюции не отвечает на вопрос "откуда взялись гены", это за гранью её применимости. Теория эволюции описывает то, как именно гены (как элементы объективной реальности) себя ведут, когда уже существуют, и в этой области теория эволюции подтверждается колоссальным набором наблюдений и экспериментов. Некоторые из них вы даже можете провести самостоятельно, вроде экспериментов по скрещиванию гороха. На вопрос откуда и как возникли гены (а заодно и прочие элементарные куски жизни) пытаются ответить различные теории вроде теории абиогенеза, и вот в них на данном этапе развития науки белых пятен довольно много, но это не является фундаментальной проблемой — так было со всеми научными теориями, они никогда не рождались уже готовыми и всегда развивались инкрементально.
Но, справедливости ради, scala-async и аналогичные механизмы в других языках в своей теоретической основе имеют как раз продолжения. Например, scala-async из async-блоков создаёт конечный автомат из продолжений, где код "после" вызовов await автоматически преобразуется в продолжение, которое будет вызвано после завершения асинхронного вызова.
Угу. CompletionStage это по сути Future в других языках. В Scala, например, Future'ы являются основной абстракцией для описания асинхронного кода, и на них определено множество комбинаторов для объединения и обработки асинхронных значений. Кроме того, с библиотеками типа scala-async код на Future'ах выглядит почти неотличимо от синхронного кода без них.
Кстати, в русскоязычной литературе continuation переводится как "продолжение".
Советую почитать сайт, на который я уже давал ссылку выше: http://utf8everywhere.org/. Вопреки распространённому представлению, случаи, когда доступ по индексу (что, вообще говоря, требует отдельного определения — доступ по индексу чего?) важен, на практике исчезающе редки, и, как правило, встречаются в коде, автор которого работает с юникодом неправильно.
Важно знать об этом и помнить; думаю Googolplex именно на это хотел обратить внимание всех читателей.
Да, всё так и есть. По моему мнению, нельзя говорить что "в таком-то языке строки в UTF-16", если этот язык позволяет легко и походя сконструировать строку, которая валидной UTF-16-последовательностью не является. Даже если этот язык и предоставляет какие-то методы для работы с суррогатными парами и даже если, скажем, методы типа reverse() умеют работать с суррогатными парами.
То, что в джаве есть методы, которые позволяют "исследовать" code point'ы UTF-16, не значит, что сами строки в ней представлены в UTF-16. Если бы в Java гарантировалась корректность того, что строка всегда валидная с точки зрения UTF-16, то тогда бы я согласился, но к сожалению это не так. Например, какой-нибудь substring() совершенно замечательно позволит распилить суррогатную пару пополам. А в Rust, например, аналогичная операция над UTF-8 строками невозможна, просто нет соответствующих методов. Если есть нужда в подобных операциях, строку всегда можно сконвертировать в срез байтов и работать с ним.
Проблема здесь в том, что в джаве работа с "символами" предоставляется таким образом, как будто строки это просто массивы char'ов (собственно, внутри так и есть), что с точки зрения UTF-16 некорректно. Пример того, как аналогичная проблема решается правильно — в Rust, где используется UTF-8 (переменной длины), и при этом гарантируется корректность внутреннего представления строки.
VLIW это не конкретная архитектура типа x86/ARM/MIPS, это скорее "стиль" набора команд. По уровню абстракции это на уровне с CISC и RISC. Например, недавно официально почивший Itanium это тоже VLIW.
Насчёт пункта 2 — тут вполне логично всё. Если мы используем wildcard, то мы явно заявляем компилятору, что мы не знаем соответствующий тип.
?
до некоторой степени эквивалентен? extends Object
, что делаетRef<?>
ковариантным; следовательно, методы, которые принимают значение типа-параметра в качестве аргумента вызывать больше нельзя. В противном случае в компиляторе должен быть механизм отслеживания того, откуда какое значение пришло, что в общем случае мне кажется эквивалентным проблеме останова.Насчёт 3 пункта мне тоже не кажется наличие проблемы очевидной. В конце концов, вы там мешаете дженерики и сырые типы, чего делать очень не рекомендуется. Решение, как вы заметили — не использовать сырые типы. Про сырые типы лучше вообще забыть в аспекте написания кода, это страшенный костыль для обратной совместимости.
Первое это вообще треш, да. Никогда правда с таким не сталкивался.
Не нужно советовать вот это:
Метод
<<=
подепрекейчен и в sbt 1.0 будет выкинут. Вместо этого следует использовать.value
или.evaluated
:Кроме того, особого смысла в этих переназначениях, имхо, вообще нет — эти таски по умолчанию будут доступны как
android:run
иandroid:install
.А для рисования используется AWT, да. Что-то производительное и сложное на этом написать трудно, Graphics и Graphics2D в первую очередь сделаны для рисования кастомных виджетов, не для сложных двигающихся изображений.
Интересно, что в Future'ах скалы это проблема решается тем, что все методы, которые принимают коллбэки, также принимают параметром executor, в котором коллбэк должен выполниться, поэтому всегда можно указать нужный executor и сериализовать обращения к мутабельному состоянию. Хотя для этого лучше конечно использовать библиотеки вроде Akka.
Типы, которые вы написали, не эквивалентны. Первое — это тип второго порядка, т.е. с сигнатурой
* -> *
. Второе — это конкретный (первого порядка) экзистенциальный тип, т.е. с сигнатурой просто*
. Грубо говоря, первый тип вы можете применить к какому-то типу и получить новый тип, второй же применять не к чему, он уже конкретный, хоть и экзистенциальный. Вот этот плагин к компилятору: https://github.com/non/kind-projector позволяет записывать такие типы удобнее.Пожалуйста, не нужно продолжать использовать эту древнюю тулзовину. Есть гораздо более адекватные современности вещи; если хочется лёгкой императивности, то можно взят тот же Gradle.
Брр, как вспоминаю рекурсивные антовые сборки из сотен файлов по несколько тысяч строк...
Пусть площадь диафрагмы фиксированная, и общая площадь матрицы тоже фиксированная. Тогда если за диафрагмой матрица с "большими" ячейками, на каждую ячейку в отдельности попадёт больше света, чем если за ней будет матрица с "маленькими" ячейками. Если на каждую ячейку попадает больше света, снимок становится в целом ярче. Здесь важен не размер матрицы в целом, а размер отдельного светочувствительного элемента.
Хочу сказать, что ставить GraphStage на один уровень с Sink и Source — это примерно как говорить, что у нас есть
Map
,Set
иLinkedList
. Утверждение корректное, ноSink
иSource
— это интерфейсы, обозначающие конец и начало стрима, аGraphStage
— это конкретная реализация стримов произвольной формы (GraphStage
может иметь форму Sink'ов, Source'ов, Flow'ов, BidiFlow'ов и прочего).Основные интерфейсы в Akka Streams это Source, Flow и Sink:
GraphStage же позволяет реализовать на низком уровне произвольную логику части стрима с произвольным количеством входов и выходов. Это очень мощная штука, но ей довольно сложно пользоваться, и, как правило, она нужна для реализации абстрактных примитивов, которые потом переиспользуются, а не для непосредственно бизнес-логики приложения. Для бизнес-логики гораздо удобнее и проще использовать акторов.
Вот этот плагин пилится разработчиками из JetBrains.
Похоже, название было выбрано по аналогии с Котлином — Гогланд это тоже остров в Финском заливе)
А почему owncloud а не nextcloud? Насколько я помню, в nextcloud ушла большая часть разработчиков owncloud, и сам он позиционируется как более свободная альтернатива.
"Механизм эволюции" — это ярлык, краткая ссылка на конкретный набор физических процессов, которые мы можем либо наблюдать, либо экстраполировать исходя из наблюдений. Поэтому некорректно спрашивать "когда был создан механизм эволюции". Он был "создан", если хотите, когда какой-то учёный, понаблюдав за природой, обнаружил некоторые закономерности и назвал их "эволюцией".
Всё то же самое относится и к критериям отбора. Они ниоткуда не возникли, потому что они не являются какой-то отдельной сущностью, как скажем камень или озеро. "Критерии отбора в механизме эволюции" это всего лишь символ, которым мы пользуемся для описания условий, при которых работает "механизм эволюции", который, в свою очередь, является краткой ссылкой на описание конкретных физических процессов, которые мы можем наблюдать.
Следовательно, некорректно уравнивать "механизм эволюции" и "бога" с точки зрения "веры" в них, потому что "механизм эволюции" определяется через физические процессы, которые мы можем непосредственно наблюдать и даже ставить эксперименты (т.е. он основан на свойствах объективной реальности), а в "бога" можно только "верить".
И заметьте, что вопрос о том, почему существуют именно такие физические процессы, которые составляют "механизм эволюции", и откуда они взялись — это совершенно другой вопрос, и совершенно другая область знания. Теория эволюции не отвечает на вопрос "откуда взялись гены", это за гранью её применимости. Теория эволюции описывает то, как именно гены (как элементы объективной реальности) себя ведут, когда уже существуют, и в этой области теория эволюции подтверждается колоссальным набором наблюдений и экспериментов. Некоторые из них вы даже можете провести самостоятельно, вроде экспериментов по скрещиванию гороха. На вопрос откуда и как возникли гены (а заодно и прочие элементарные куски жизни) пытаются ответить различные теории вроде теории абиогенеза, и вот в них на данном этапе развития науки белых пятен довольно много, но это не является фундаментальной проблемой — так было со всеми научными теориями, они никогда не рождались уже готовыми и всегда развивались инкрементально.
Но, справедливости ради, scala-async и аналогичные механизмы в других языках в своей теоретической основе имеют как раз продолжения. Например, scala-async из
async
-блоков создаёт конечный автомат из продолжений, где код "после" вызововawait
автоматически преобразуется в продолжение, которое будет вызвано после завершения асинхронного вызова.Угу. CompletionStage это по сути Future в других языках. В Scala, например, Future'ы являются основной абстракцией для описания асинхронного кода, и на них определено множество комбинаторов для объединения и обработки асинхронных значений. Кроме того, с библиотеками типа scala-async код на Future'ах выглядит почти неотличимо от синхронного кода без них.
Кстати, в русскоязычной литературе continuation переводится как "продолжение".
Вернее, в Rust методы есть (например, слайсинг строк типа
s[1..3]
), но эти методы будут паниковать, если смещения указывают в середину code point'ов.Советую почитать сайт, на который я уже давал ссылку выше: http://utf8everywhere.org/. Вопреки распространённому представлению, случаи, когда доступ по индексу (что, вообще говоря, требует отдельного определения — доступ по индексу чего?) важен, на практике исчезающе редки, и, как правило, встречаются в коде, автор которого работает с юникодом неправильно.
Да, всё так и есть. По моему мнению, нельзя говорить что "в таком-то языке строки в UTF-16", если этот язык позволяет легко и походя сконструировать строку, которая валидной UTF-16-последовательностью не является. Даже если этот язык и предоставляет какие-то методы для работы с суррогатными парами и даже если, скажем, методы типа reverse() умеют работать с суррогатными парами.
То, что в джаве есть методы, которые позволяют "исследовать" code point'ы UTF-16, не значит, что сами строки в ней представлены в UTF-16. Если бы в Java гарантировалась корректность того, что строка всегда валидная с точки зрения UTF-16, то тогда бы я согласился, но к сожалению это не так. Например, какой-нибудь substring() совершенно замечательно позволит распилить суррогатную пару пополам. А в Rust, например, аналогичная операция над UTF-8 строками невозможна, просто нет соответствующих методов. Если есть нужда в подобных операциях, строку всегда можно сконвертировать в срез байтов и работать с ним.
Проблема здесь в том, что в джаве работа с "символами" предоставляется таким образом, как будто строки это просто массивы char'ов (собственно, внутри так и есть), что с точки зрения UTF-16 некорректно. Пример того, как аналогичная проблема решается правильно — в Rust, где используется UTF-8 (переменной длины), и при этом гарантируется корректность внутреннего представления строки.