MusicXML - он не для ручного ввода - а для автоматикой (в т.ч. кроссплатформенной) интеграции - как раз для копи/паста мог сгодиться...
Так же MusicXML априори очень гибкий и расширяемый формат. Например, в "ORANGE" помимо общих форматов музыкальных потоков WAVE и MIDI возможны и потоки в других форматах (пока сугубо теоретические - этот вопрос ещё не проработан, но заложен изначально), среди которых может быть и MusicXML; а так же запланирован (но может откажусь и буду расширять MusicXML) проприетарный открытый формат (кстати, рассматривалась база XML, JSON, Protobuf) - для более расширенного управления компонентами (как в качестве внутреннего протокола, так и для взаимодействия со сторонними компонентами). Просто у меня запланировано куда более сложное командное взаимодействие, чем набор MIDI-событий, в т.ч. с целью управления параметрами и техниками звукоизвлечения комплексных компонент (а-ля какие использует Kontakt)
мой пример было не про опции, а про работу с null значениями - я специально старался его абстрактно написать, а "CustomOptions["Allow"] " просто привёл как понятный источник null значения, но я не указывал его физическую природу - это может быть и карта "ключ-значение" (фиг его знает откуда полученная) - или обращение какому-либо хранилищу - хоть локальному, хоть БД, или какой-либо ещё комплексный сервис - который пытает получить значение из данных, собираемых их различных источников. ИМХО - алгоритму основной логики это всё должно быть сугубо "фиолетово" - у него есть источник "CustomOptions" - вот там он будет искать значение. А если его там нет - у него есть некий процесс иного поучения этого значения, которые тоже не гарантирует успех - и только затем значение берётся из кода - для случая, когда без него дальше никак не обойтись, но по какой-то непонятной причине оно так и не было получено!
Ну а в финале - передаём (во втором случае пытаемся) значение в нужные объекты - чтобы так больше не "мучиться" и для того, что это значение ещё где-то важно должно быть - если это "где-то" существует! Не вдаваясь в подробности того - как эти все вспомогательные объекты устроены!
Понятное дело, что вы будете топить за свой ЯП всеми правдами и неправдами.
Я не собираюсь топить за свой ЯП! Как и топить другие системы (ну кроме Native instruments Kontakt - уж больно она меня разочаровала (хотя шутка, бесспорно, полезная); как и разочаровало, например, и развитие Sony Acid - который теперь мультикомбайн Vega, Cakewalk - который теперь Sonar (и многие другие мультидорожечники) - но это для тех кто в курсе). И готов принять любую критику своих идей - главное чтобы было обоснование, даже если я его сочту спорным - обоснованная критика - всё равно полезная критика!. И я не пытаюсь необоснованно критиковать вашу разработку. Напротив - я всячески желаю Вам удачи с ней!
И сути это не меняет - нельзя ошибиться в названии переменной, если его нельзя напечатать, а можно только выбрать из списка. Нельзя ошибиться с пропущенной кавычкой, если кавычек тоже нету. Нельзя перепутать "=" или "==" в условии, если "=" тоже нету
Как я выше написал - всем есть своя цена - и всего есть плюсы и минусы. И где есть минусы - их стараются "пусть порой условно и костылями" эти минусы устранять! И таких наработок для текстовых процессоров уже уйма - так что если сравнивать кодинг лет пятьдесят назад и сейчас - это будет гигантский разрыв (даже в рамках одного текстового ЯП)! Даже за последние 10 лет IDE шагнули очень далеко вперёд. А сейчас, на волне, генеративных лингвистических алгоритмов - шагнут ещё сильнее!
(Кстати, у Вас есть имена модулей, и да - вы позволяете их выбирать из списка (как, впрочем, это позволяют и быстрые всплывающие подсказки ввода) - но решаете ли Вы проблему, когда - это имя потом меняется у модуля - везде где используется переназначаться? Для визуальных систем это, правда, плёвое дело - а текстовые процессоры пришли к решениям не так давно - рефакторинг изменения и подсчёт с отображением ссылок - но 100% надёжности это не даёт... впрочем наврядлли сейчас хоть где-то есть 100% надёжность при активном повторном использовании кода и библиотек)
А, вот, куда сейчас развиваются музыкальные редакторы (априори визуальные) - мне категорически не нравится - это навороченные визуальны монстры с красивой графической обёрткой - и скудным сложным содержимым (я не буду говорить про плагины - среди которых есть и не скудные но от того не менее простые приложения)! Вот тут действительно назрела революция! Когда-то такой был Трекерный редактор, Piano roll, драмм-машина, , затем технология VST-плагинов, затем виртуальных DSP-процессоров и мультидорожечных редакторов и наконец музыкальных приложений для платформы Kontakt (ну я не все знаковые технологии в музыко-строении перечислил). Пришла пора двигаться дальше...
Нельзя ошибиться с разыменованием NULL в рантайме, если NULL-ов тоже нету (а вместо них есть значения/объекты по умолчанию).
Вот за это всецелое УРА! Учли опыт величайшей ошибки Дейкстры! Я тоже против NULL но....
для обхода NULL придумали и целе семейство null-операторов (?. ?? ??=) и отделили nullable определения переменных/свойств от не-nullable - и это отличное подспорье - появились очень интересные и удобные техники их применения!
С NULL очень удобно и красиво решается - без NULL приводит к старом заскорузлому некрасивому (хоть и понятному) коду!
Bool? Enabled = CustomOptions["Allow"] ?? (Object as ICheckable)?.Checked; Enabled ??= A?.B?.C?.Checked ?? true; CustomOptions["Allow"] = Enabled; //A?.B?.C?.Checked ??= Enabled; //Вот это, правда, в C# не прокатит
Так оставляйте в стороне и вспомогательные средства IDE для быстрого ввода в виде автодополнения, подсветки синтаксиса и проверки орфографии, а то как-то нечестно получается
Если внимательно читали - то я при оценке времени так и сделал. И указал - что с данными средствами будет и ещё быстрее и надёжнее
Просто Ваш аргумент он не имеет значимой силы
Интересно - кто минус моему комментарию выше поставил - за что (если это вы просто в отместку - то я не минусовал ваш комментарий)
Тут всё зависит от подходов к разработке и среды. Чем жёстче подходы - тем меньше комфорта и универсальность - но выше контроль.
А подобные опечатки текстовые IDE в 99.98% случае сами находят ещё на стадии окончания ввода слова! А некоторые продвинутые IDE ещё и сразу могут исправлять! Не говоря уже о быстрых подсказках автоподстановки - которые в умелых руках (и умелом текстовом процессоре) в более чем 80% случае просто позволяют избегать таких ошибок!
(не ключевые слова, уже определённых идентификаторов или литералов - так же будут выделяться цветом; а при мало-мальски грамотном назначении имён идентификаторов - вероятность ошибиться и из-за опечатки ввести другое имя существующего идентификатора - практически равна нулю - и современные IDE могут сразу автоматически исправлять такие опечатки)!
У визуальных сред куча своих проблем - часть я в комментариях к этой статье уже описал - но это далеко не полный список!
То же зарезервированное слово для определения сущности "instrument" - в текстовом редакторе вводится за 1.5-2 секунды (кото-то и быстрее введёт, я уж не говорю о шаблонах и копипасте, и быстрых подсказках ввода) - ошибка в тестовых процессорах будет видна сразу (это же ключевое слово - оно не будет выделено соответствующим образом) - и на её осознание и исправление (требующееся очень редко) уйдёт ещё секунды 2-3.
А сколько времени уйдёт в визуальном редакторе размещение такого компонента на поле (так оставим в стороне вспомогательные средства быстрого ввода): надо где-то нажать кнопку с командой добавления компонента, затем выбрать его из списка, или воспользоваться текстовым поиском, кликнуть по кнопке добавления, перенести его в нужное место на плоскости (а то ещё и другие компоненты подёргать) - это десятки секунд.... а потом окажется что это не тот компонент, что нужен (например, промахнулись - не туда кликнули)...
То же и про пропущенную кавычку - обычно это всё легко видно - небольшие сложности только в интерполяционных строках бывают - но были бы такие у Вас - были бы такие же проблемы, скорее всего - но это всё мелкие проблемы - и быстро исправляются.
P.S.
Вот опечатка с MIDI там где нужна WAVE именно в моём ЯП всплыла- бы только при компиляции - когда драйвер устройства WASAPI не смог бы по типам данных спрячься с типом данных, передаваемых из канала! Но это уже нюансы ЯП гибкой статической типизации - точные типы появляются только при компиляции!
Упущенный параметр "Input=InputChanel2" для "Track2" (без специально настроенных анализаторов) всплыл бы только при отладке - параметр не обязательный (как и то, что у трека может не быть входного канала данных - когда он сами их статически описывает или генерирует, или откуда-то загружает) в своём теле - внутри { }; или в трек могут напрямую отправляться инструкции из другого трека (трек сначала может динамически наполняться, а потом только воспроизводиться, или не обязательно воспроизводиться, а, скажем, выгружаться на диск в файл/БД, или передаваться в другую программу, в т.ч. по сети)!
Пропущенное указание треков, которые надо стартовать при старте проекта - это скорее нюансы дизайна ЯП - может действительно не надо стартовать никаких треков - а при старте проекта нужно выполнить сначала подготовительные алгоритмы... но можно, конечно ввести какую-то конструкцию - указывающую на это - и когда ничего нет - хотя бы выдавать предупреждение при компиляции
Для составления инструкций алгоритма работы в среде требуются знания не столько в программировании, сколько в знаниях внешней аппаратной части бинарной логики управления.
Скажу так - в этом конкретном случае лишь три проблемы:
Отсутствие правильно архитектурно подготовленных библиотек и документации к ним
Отсутствие настроенных кодогенератор, отладчиков и прочего суппорт-софта для данной среды
Я же выше написал - что системное программирование ещё долго будет с нами - и там будет править классика. Но, объёмы такого программирования будут год от года снижаться. А вот объёмы кодогенерации, в т.ч. и в области системного программирования будут год от года расти. А визуальное и декларативное программирование будут как раз стоять на фундаменте низкоуровневой кодогенерации и некоторых системных готовых библиотеках!
Я ни разу не говорил, что Ваше решение - не рабочее и не может иметь практической ценности или быть популярным в определённых кругах. А так да - только практическое применение и отзывы могут показать эффективность того или иного подхода. У меня пока нет рабочего решения :-(
Про повторное использование кода, кодогенерацию и шаблоны, и разбиение по файлам/модулям - я уже написал выше. И уверен - даже незнакомые с построением DSP-плагинов люди, сходу поймут что да как тут происходит и настраивается! Не говоря уж про строки комментариев - и прочее самодокументированние!
Да и ЯП "Orange" - задуман как куда более мощная "штука", чем просто DSP-фильтр - так что тут есть "место" для боллеплейт-кода - но всё это можно вынести в повторноиспользуемый код -или применять шаблоны! Да и с некоторым "синтаксическим сахаром" это всё можно несколько было упростить - для простых случаев
P.S. Хотя компиляция проекта в DSP-фильтр или VST-плагин - тоже вполне возможна
Была проращена открывающая кавычка: Driver = WASAPI("Динамики (Realtek High Definition Audio)"
Опечатка "instrumnet"->"instrument"
В обоих OutputChanel ошибочно указал формат MIDI - там, конечно же WAVE - но может быть и MIDI - но тогда VSTi семплер будет проигнорирован (если он не сможет выдавать MIDI поток)
В "Track2" забыл указать параметр "Input=InputChanel2" для настройки канала, по которому в трек будут поступать MIDI события!
При старте проекта хорошо было бы указать и стартуемые треки, ну или аннотировать их как автотстартуемые вместе с проектом (а вообще треки могу запускаться (и останавливаться) в произвольный момент времени - мануально, по расписанию, по событию и другими способами - тут полная гибкость): run MyProject with track(Auto) [MyLayer.Track1, MyLayer.Track2]
У значений перечислений без указания полного пути идентификатора - по-хорошему надо бы поставить точку перед идентификатором значения - чтобы синтаксический разбор понимал, что надо проанализировать тип приёмника для идентификации полного имени значения - но, будем считать, что можно и без точки, когда нет пересечений идентификаторов в текущем контексте - опция настройки проекта)
Примечания:
Маппинг каналов скорее лучше делать через отдельный компонент Mixer - но для простоты не стал его указывать - а вообще - в мультиканальном проекте с пространственным 3D0звучанием такой компонент может активно применяться!
Вместо указания параметра инструмента "ProgramFIxed" (что скорее для инструментов, которые не поддерживают разные программы звучания) лучше настроить у InputChanel компонент фильтра - для отбрасывания MIDI инструкций смены инструмента:
Пример фильтрации в каналах
chanel InputChanel1 {
Direct = Input Format = MIDI Source = InputDevice1 Filter = MIDIBoolFilter {
return MIDIEvent.Command != ProgramChange)
} //Задали произвольный алгоритм фильтра MIDI сообщений - пропускаются только "истинные" MIDI события
}
chanel InputChanel2 {
Direct = Input Format = MIDI Source = InputDevice2 Filter = MIDIEventFilter {
} //Задали произвольный алгоритм фильтра MIDI сообщений - подменяющий сообщения по смене программы на пустую команду (в условии нет секции "иначе" - она генерируется автоматически - исходным значением событий); а, в принципе, такой фильтр может и другие преобразования делать (для WAVE-формата канала тоже свои фильтры могут быть - но там, их лучше подключать как DSP-процессоры - между каналами)
} //Задали произвольный алгоритм фильтра MIDI сообщений - подменяющий сообщения по смене программы на пустую команду (в условии нет секции "иначе" - она генерируется автоматически - исходным значением событий)
Музыкальный трек организован куда сложнее - чем показано в данном примере - он может обслуживать мульти-инструменты, мульти-эффекты, полифонию, мульти-семплирование, мульти-каналы и т.д. и т.п. По сути - трек - это просто некоторая агрегация сервиса воспроизведения (как и слой, как и, не указанный здесь, score - для разделения партитур) - все они определяют свой контекст воспроизведения
Главное преимущество визуального программирования - отсутствие необходимости именования переменных/объектов и ещё больше возможностей для инкапсуляции
Я бы назвал это преимущество весьма сомнительным. Да - можно - но много ли от этого толку... а сколько это в итоге порождает проблем в сложных схемах... Насколько это поддаётся эффективной и продвинутой отладке... Насколько это всё само документируемо, и поддаётся созданию отдельной документации...
Поэтому в своё примере выше - у меня все узлы именованы (кроме узлов проекций/фильтров - это порты, принадлежащие своим узлам, но - в принципе им, как и линиям тоже можно было бы вешать лейблы)! А так - как, в другом комментарии выше, я показывал - можно и анонимную лямбду создать - и передать её в другой блок!
И обратите внимание - графической связи между клавиатурами и синтезатором нет, она задаётся в свойствах
Да, при визуализации вполне допустимо - но, опять же, очень спорное решение - усложняет понимание схемы!
А насчёт примера.... ну я тут выше в комментарии уже приводил примеры своего ЯП для музыки "ORANGE" - он текстовый и на нём ваш пример (в котором, правда большая часть информации отсутствует в обоих вариантах представления) выглядел бы так:
пишу целиком, включая шапку, без особых синт. сокращений:
project MyProject {
device OutputDevice1 {
Direct = Output //Не обязательно - т.к. это по умолчанию так Format = MIDI Driver = WASAPI(Динамики (Realtek High Definition Audio)" ChanelsMap = {Left->"L", Right->"R", BackLeft->"BL", BackRight->"BR"}
}
device OutputDevice2 {
Direct = Output //Не обязательно - т.к. это по умолчанию так Format = MIDI Driver = WASAPIOut("LG ULTRAGEAR (Аудио Intel(R) для дисплеев)") ChanelsMap = {Left->"L", Right->"R"} //Не обязательно - т.к. это по умолчанию так (когда у устройства нет других каналов)
}
device InputDevice1 { Direct = Input Format = MIDI RAWFormat = Int RAWConverter = System.Converters.ToMIDI.KeyboardScanCodeToMIDI Driver = KeyboardInput //Если я правильно понял – что источников является букво-цифровая клавиатура RAWInternalConverter += @AnotherFunction //Если нужен какой-то свой обработчик конвертации потока кодов клавиатуры в MIDI инструкции ChanelsMap = {Mono->"1"}
}
device InputDevice2 {
Direct = Input Format = MIDI Driver = MIDIInput("LoopBe Intenral") //Какой-то MIDI input - из примера не ясно как он настроен ChanelsMap = {Mono->"1"}
}
chanel OutputChanel1 {
Direct = Output //Не обязательно - т.к. это по умолчанию так Format = MIDI Space = STEREO //Не обязательно - т.к. это по умолчанию так Destination = OutputDevice1 ChanelsMap = {Left->Left, Right->Right} //Маппинг только в два канала устройства воспроизведения
}
chanel OutputChanel2 { Format = MIDI Destination = OutputDevice2 //ChanelsMap = {Left->Left, Right->Right} //Не требуется, т.к. тут маппинг по умолчанию в два доступных у устройства канала
}
chanel InputChanel1 {
Direct = Input Format = MIDI Source = InputDevice1
}
chanel InputChanel2 {
Direct = Input Format = MIDI Source = InputDevice2
}
sampler S_yxg50_Sampler { Format = VSTi Path = FilePath("c:\vst\yamaha\syxg50.dll":raw) Space = STEREO //Не обязательно - т.к. это по умолчанию так ChanelsMap = {Left->"01", Right->"02"}
}
instrument S_yxg50 {
Destination = S_yxg50_Sampler Program = 8 //Вообще инструмент подразумевает фиксацию программы синтезатора здесь (т.к. именно инструмент определяет настройки звучания), но в примере она фиксируется только для одного Midi input (вероятно у другого - другая программа) - такое тоже возможно (здесь только значение по умолчанию)
}
layer MainLayer {
track Track1
{
useinstrumnet S_yxg50(ProgramFixed=true) useinput InputChanel1 useoutput [OutputChanel1,OutputChanel2] //В моей схеме не семплер подключается к каналам вывода, а музыкальный трек (здесь подключение сразу к двум каналам runtimeinput:loop //трек активен только в runtime режиме в бесконечном цикле воспроизведения
}
track Track2 ( Instrumnet=S_yxg50(Program=3, ProgramFixed=true) //Сменили программу (тут будет клон инструмента) Output = [OutputChanel1,OutputChanel2]
) @RuntimeInput(lnfinity) //аннотация режима исполнения трека
}
Layers=[MainLayer]
}
run MyProject
Надеюсь ничего не забыл, и правильно понял исходный пример. Да - может код несколько многословен - но тут много базового конфигурирования идёт. У Вас же, в визуальной части, настройки делаются в узлах - и не отображаются, но их всё-равно надо делать (текст тоже можно скрыть в сворачиваемых блоках, распихать по файлам и подключаемым модулям библиотек, в т.ч. для повторного использования), ну и текст легко комплексно просматривается, и легко рефакторится, и легко публикуется и передаётся куда-либо, да хоnть в Git
И да - всё-таки ЯП ORANGE хоть и спроектирован для реализации runtime MIDI-ввода - но, всё же, создан больше для кодирования воспроизведения в виде инструкций к семплерам (что можно делать и в runtime; или направлять MIDI инструкции из источника в генератор кода в инструкциях ЯП Orange)!
потому что для каждого объекта предусмотрено клавиатурное сокращение, например "kbd" или "midiin", после чего он появляется в позиции курсора.
Ну - для этого возможны:
Шаблоны быстрого ввода в текстовом процессоре IDE (в т.ч. привязанные к macros и static instument generators, которые могут читать конфигурацию из внешнего config-файла, а так же иметь доступ к AST-дереву выражений проекта - чтобы генерировать код максимально гибко и адаптивно; но я не говорю - что такое в принципе нельзя сделать при визуальной разработке - но инструментарий IDE должен быть очень продвинутым, в отличии от текстовых процессоров - где это либо уже реализовано, либо легко подключается плагинами, либо вообще решается на уровне компилятора и/или внешнего текстового препроцессора)
Просто готовые преданстроенные функции внутри проекта или во модулях библиотек - которые просто можно вызвать (в т.ч. с параметрами) - а они уже проведут всю общую настройку - в этом преимущество классического подхода кодирования исходников - в гибком повторном использовании кода (но я не говорю - что такое в принципе нельзя сделать при визуальной разработке)
Есть одно пересечение от функции "Process" к "B" (в идеале там должно быть "мостик" - рисовал в ""Miro" - не поддерживает, видимо) - но, замечу, что как раз в этой схеме его можно избежать, нарисовав линию стрелки в другую сторону (обогнув функцию "Process2")! Кстати, IDE может иметь средство перераспределения схемы/части схемы - для минимизации пересечений.
В более сложных схемах могут применяться разные способы избежание пересечений или решения проблем их читаемости. Например, можно клонировать состояние системы в узле "А" (переменной/источнике/примёнике) - и нарисовать его ниже отдельно - так чтобы его связи не мешали другим. Или размещать их на разных слоях (в т.ч. с настроенной прозрачностью или цветами линий - чтобы даже в неотображаемом или полуотображаемом случае видеть намёки, что тут есть и другие связи). Можно и сами линии группировать через промежуточные узлы - и начинать из них движения тоже где-то ниже. Можно просто часть линий выносить в узел субпрограммы, который в основном режиме отображается как просто узел, а при детализации (как написал выше - это легко делать просто масштабированием схемы, ну или просто кликом по лупе в этом узле) - уже отображать отдельно его структуру. И так далее и тому подобное - вариантов как синтаксических так и средств IDE может быть много! Не думаю, что это такая уж проблема. Тем более, что я, ту не требую целостности графа, а в большинстве случаев такого большого числа переходов из одного узла вряд ли будет - на картинке уж очень специфическая ситуация - чаще всего инструкции достаточно линейны (ветвления условий и матчей - скорее всего не будут шибко обширными или хорошо сворачиваются, по указанным выше, или иным, методикам), а распараллеливания - вполне можно достаточно эффективно разнести друг от друга.
Кстати, IDE может даже представлять схему в разных вариантах компоновки - просто меняя способы её отображения (фактически не переставляя сами элементы) - что позволяет легко подстраивать её анализ под разные ситуации
У визуального программирования есть пара интересных архитектурных преимуществ - перед текстовым:
Очень удобно управлять множественными потоками данных - в т.ч. ветвлениями или дублированием (см. пример ниже). От одного источника легко может исходить несколько переходов. И на эти переходы можно удобно накалывать разные условия или метки аннотаций - задающие логику работы. Более того, на источник и на приёмник можно вешать как бы специальные порты - проекции/фильтрации - так что все исходящие или, соответственно, входящие линии переходов, из/в эти порты, будут подвержены зависимы от действий, заданных в этих портах - и на один источник/приёмник можно повесить сразу несколько разных портов! Так же, множественные переходы могут удобно определять и параллельное выполнение этих операций (в т.ч. в режиме по умолчанию, когда компилятор сам решает как лучше выполнять эти действия - в отдельном потоке или последовательно - в зависимости от настроек контекста выполнения и специальных хинтов-аннотаций со стороны программиста)
В отличии от представления инструкций/деклараций в текстов - которых по сути линейны - графические схемы размещаются на плоскости - а, в принципе, в 3D и даже в большем числе измерений - что позволяет более наглядно размещать связи между элементами и вложенные блоки. Тут же можно сказать и про уровень масштабирования - когда можно приближая масштаб легко переходить от общего узла некоторого блока - к его внутренней реализации, оставаясь в текущем контексте, что позволяет (при необходимости), например, вместо внутренней логики подпрограммы (читай функции) подставлять идентификаторы текущего контекста - чтобы лучше понимать как внешняя среда влияет на результат внутренней
В схеме выше много действий. Условно начало можно считать получение фильтра FilterList (хотел сначала сделать точку входа Request - но передумал - и так сложно вышло)
Ключевым тут является источник переменной "A" (тип который является перечислимым) - у неё есть ряд исходящих портов разного типа - какие-то передают все данные переменной "A" (но только если сущность переменной "A" удовлетворяет условиям); какие-то передают только часть её содержимого - поэлементно удовлетворяющие условию. Так же тут осуществляются операции фильтрации данных по типам и контрактам (забыл добавить и просто операции преобразования)
Есть даже паттерн переназначения фильтра по умолчанию (он не изменяет передачу типа данных, но все условия на него, накладывается согласно заданного шаблона)
Короче - схема, безусловно очень абстрактная, но я просто хотел показать возможную глубину фишек визуального программирования на графических схемах
Кто его знает - сейчас трудно дать чёткую оценку тому, как будут программировать роботов лет через 100-200
Но Вы учтите - что лет за 100 и текущее - текстовое программирование в своей массе тоже сильно видоизменится! Как это уже происходило - пару раз - сначала переходом от перфокарт/перфолент как раз так и к примитивному текстовому вводу инструкций (от ассемблера до С++ и далее)- а затем второй раз - к более абстрактному программированию намерений (от Lisp/Prolog до SQL/NoSQL и далее). А современные ЯП - это скорее уж химеры, сочетающие стороны обоих подходов! Но я верю в то, что большая часть прикладного программирования будет всё больше уходить в обобщённое абстрактное программирование - в декларативной форме... такое, что гуру ЭВМ прошлого века точно бы не назвали классическим программированием - а уж противников, считающих, такой подход извращённым есть сейчас и будет через сотни лет - ещё вполне много - системное программирование навряд ли далеко уйдёт за ближайшие лет сто от прямых инструкций... Но роботов явно не будут программировать ни дома ни на "заводе" прямыми инструкциями - так что ЯП для них, что примышлённый, что домашний - вряд ли будут сильно отличаться по своим возможностям (но доступ к библиотекам и доступ к данным настроек - конечно будет различный, как и сложность этих библиотек и настроек - как это есть и сейчас - не всем дано ковыряться в недрах ядра ОС или БИОС, или даже системном меню бытовой техники)!
Кстати, восприятие визуального программирования, так сказать, массами может очень сильно измениться в ближайшие полвека. Если ещё лет десять-двадцать назад в школах программирование учили вяло и именно на классике - т.е. текстом. То сейчас ситуация сильно меняется - в школах активно начинают изучить программирование именно с графических систем, специально созданных для детей - типа Scratch - и это правильно - и это будет закладывать совсем иное и углублённое отношение к визуальным ЯП среди новых поколения - и чем больше будут уделать внимания разным графическим системам именно со школьной скамьи - тем ярче будет желание (как и не желание) - программировать и во взрослой жизни с применением визуальных сред. Но тут уже как душа у кого ляжет - но, всё-таки, некоторое привыкание к визуальному программированию будет с детства, а не так как у большинства нынешних уже состоявшихся программистов - которые хорошо освоили текстовый подход - и смотрят на иные средства как на что-то чужеродно!
Да и сами визуальные ЯП за ближайшие десятилетия, а то и столетие - подтянутся - и будут ещё более удобными, приятными и мощными в использовании - чем текстовая классика - но вряд ли они смогут вытеснить текстовый подход - скорее они его дополнят!
Мне кажется до домохозяек тоже это дойдёт - и тому будут две причины:
Продвинутые специализированные фреймворки "для чайников" + AI ассистенты + графическая визуализация (да хоть структурированная, да хоть по частям) дадут колоссальную поддержку в формировании программного кода
Людям придётся осваивать и программирование роботов так же как и когда-то пришлось осваивать бытовую технику, смартфоны и домашние компьютеры + я считаю, что повысится и уровень образовательной программы, подстраивающийся под реалии прогресса и быт, требующий более сложных знаний + будет совершенствоваться и автоматизироваться, и, в то же время, образовательная программа и средства обучения - дети уже с детского сада будут окружены цифровыми технологиями и индивидуальным подходом - думаю, что, и итоге, сам термин "домохозяйка" в текущем, чаще негативном интеллектуальном окрасе, уйдёт в прошлое - общий уровень повысится....
но.... безусловно, возможен и обратный процесс (и он весьма вероятен) - когда всеобщая автоматизация наоборот будет отталкивать людей от самосовершенствования и развития - всё больше направляю их по деградационной шкале к уровню животных - которым и корм дадут, и лоток уберут, и на прогулку выведут, и развлекут...
Но я не верю в долгое нахождение в промежуточном состоянии развития - оно не устойчиво - ведомое AI и тотальной автоматизацией человечество пойдёт в своём развитии либо в верх либо вниз (но возможны и периодические колебания - с длительными циклами нахождения в том или ином состоянии - тут многое зависит от того - как с таким человечеством справится этот самый AI - сумеет о его сохранить и направить на путь развития - или сочтёт это дело бессмысленным)!
Но всё это, на мой взгляд, ещё очень не скоро ждёт человечество - и деградация, и домашнее повсеместное программирование роботов, да и сами повсеместно распространённые роботы и продвинутый ИИ - я думаю от этого нас ещё отделяют столетия развития технологий....если за это время человечество не умудрится и без ИИ отправить себя в каменный век!
Но... тем не менее.... домашние программируемые роботы появятся, скорее всего уже во второй половине XXI века, пусть и с примитивным AI
Но программировать роботов на бытовом уровне, всё-таки, будет проще голосом - но на телевизоре/планшете может выводиться какая-то вспомогательная графическая информация
Не кажется Вам, что это слишком громоздко? Время Piano roll прошло...
MusicXML - он не для ручного ввода - а для автоматикой (в т.ч. кроссплатформенной) интеграции - как раз для копи/паста мог сгодиться...
Так же MusicXML априори очень гибкий и расширяемый формат. Например, в "ORANGE" помимо общих форматов музыкальных потоков WAVE и MIDI возможны и потоки в других форматах (пока сугубо теоретические - этот вопрос ещё не проработан, но заложен изначально), среди которых может быть и MusicXML; а так же запланирован (но может откажусь и буду расширять MusicXML) проприетарный открытый формат (кстати, рассматривалась база XML, JSON, Protobuf) - для более расширенного управления компонентами (как в качестве внутреннего протокола, так и для взаимодействия со сторонними компонентами). Просто у меня запланировано куда более сложное командное взаимодействие, чем набор MIDI-событий, в т.ч. с целью управления параметрами и техниками звукоизвлечения комплексных компонент (а-ля какие использует Kontakt)
мой пример было не про опции, а про работу с null значениями - я специально старался его абстрактно написать, а "CustomOptions["Allow"] " просто привёл как понятный источник null значения, но я не указывал его физическую природу - это может быть и карта "ключ-значение" (фиг его знает откуда полученная) - или обращение какому-либо хранилищу - хоть локальному, хоть БД, или какой-либо ещё комплексный сервис - который пытает получить значение из данных, собираемых их различных источников. ИМХО - алгоритму основной логики это всё должно быть сугубо "фиолетово" - у него есть источник "CustomOptions" - вот там он будет искать значение. А если его там нет - у него есть некий процесс иного поучения этого значения, которые тоже не гарантирует успех - и только затем значение берётся из кода - для случая, когда без него дальше никак не обойтись, но по какой-то непонятной причине оно так и не было получено!
Ну а в финале - передаём (во втором случае пытаемся) значение в нужные объекты - чтобы так больше не "мучиться" и для того, что это значение ещё где-то важно должно быть - если это "где-то" существует! Не вдаваясь в подробности того - как эти все вспомогательные объекты устроены!
//A?.B?.C?.Checked ??= Enabled;
но можно написать вот так (тоже вполне коротко, красиво и читаемо):
if (A?.B?.C.Checked is not null) A.B.C.Checked = Enabled;
P.S.
Введение NULL - "Ошибка на миллиард долларов" не Дейкстры, а Хоара (впервые появился NULL в ЯП ALGOL W ) - всё время путаю
Вопрос скорее про интеграцию с платформой
Я не собираюсь топить за свой ЯП! Как и топить другие системы (ну кроме Native instruments Kontakt - уж больно она меня разочаровала (хотя шутка, бесспорно, полезная); как и разочаровало, например, и развитие Sony Acid - который теперь мультикомбайн Vega, Cakewalk - который теперь Sonar (и многие другие мультидорожечники) - но это для тех кто в курсе). И готов принять любую критику своих идей - главное чтобы было обоснование, даже если я его сочту спорным - обоснованная критика - всё равно полезная критика!. И я не пытаюсь необоснованно критиковать вашу разработку. Напротив - я всячески желаю Вам удачи с ней!
Как я выше написал - всем есть своя цена - и всего есть плюсы и минусы. И где есть минусы - их стараются "пусть порой условно и костылями" эти минусы устранять! И таких наработок для текстовых процессоров уже уйма - так что если сравнивать кодинг лет пятьдесят назад и сейчас - это будет гигантский разрыв (даже в рамках одного текстового ЯП)! Даже за последние 10 лет IDE шагнули очень далеко вперёд. А сейчас, на волне, генеративных лингвистических алгоритмов - шагнут ещё сильнее!
(Кстати, у Вас есть имена модулей, и да - вы позволяете их выбирать из списка (как, впрочем, это позволяют и быстрые всплывающие подсказки ввода) - но решаете ли Вы проблему, когда - это имя потом меняется у модуля - везде где используется переназначаться? Для визуальных систем это, правда, плёвое дело - а текстовые процессоры пришли к решениям не так давно - рефакторинг изменения и подсчёт с отображением ссылок - но 100% надёжности это не даёт... впрочем наврядлли сейчас хоть где-то есть 100% надёжность при активном повторном использовании кода и библиотек)
А, вот, куда сейчас развиваются музыкальные редакторы (априори визуальные) - мне категорически не нравится - это навороченные визуальны монстры с красивой графической обёрткой - и скудным сложным содержимым (я не буду говорить про плагины - среди которых есть и не скудные но от того не менее простые приложения)! Вот тут действительно назрела революция! Когда-то такой был Трекерный редактор, Piano roll, драмм-машина, , затем технология VST-плагинов, затем виртуальных DSP-процессоров и мультидорожечных редакторов и наконец музыкальных приложений для платформы Kontakt (ну я не все знаковые технологии в музыко-строении перечислил). Пришла пора двигаться дальше...
Вот за это всецелое УРА! Учли опыт величайшей ошибки Дейкстры! Я тоже против NULL но....
для обхода NULL придумали и целе семейство null-операторов (?. ?? ??=) и отделили nullable определения переменных/свойств от не-nullable - и это отличное подспорье - появились очень интересные и удобные техники их применения!
С NULL очень удобно и красиво решается - без NULL приводит к старом заскорузлому некрасивому (хоть и понятному) коду!
Bool? Enabled = CustomOptions["Allow"] ?? (Object as ICheckable)?.Checked;
Enabled ??= A?.B?.C?.Checked ?? true;
CustomOptions["Allow"] = Enabled;
//A?.B?.C?.Checked ??= Enabled; //Вот это, правда, в C# не прокатит
Вот попробует без поддержки NULL такое написать
Если внимательно читали - то я при оценке времени так и сделал. И указал - что с данными средствами будет и ещё быстрее и надёжнее
Просто Ваш аргумент он не имеет значимой силы
Интересно - кто минус моему комментарию выше поставил - за что (если это вы просто в отместку - то я не минусовал ваш комментарий)
Тут всё зависит от подходов к разработке и среды. Чем жёстче подходы - тем меньше комфорта и универсальность - но выше контроль.
А подобные опечатки текстовые IDE в 99.98% случае сами находят ещё на стадии окончания ввода слова! А некоторые продвинутые IDE ещё и сразу могут исправлять! Не говоря уже о быстрых подсказках автоподстановки - которые в умелых руках (и умелом текстовом процессоре) в более чем 80% случае просто позволяют избегать таких ошибок!
(не ключевые слова, уже определённых идентификаторов или литералов - так же будут выделяться цветом; а при мало-мальски грамотном назначении имён идентификаторов - вероятность ошибиться и из-за опечатки ввести другое имя существующего идентификатора - практически равна нулю - и современные IDE могут сразу автоматически исправлять такие опечатки)!
У визуальных сред куча своих проблем - часть я в комментариях к этой статье уже описал - но это далеко не полный список!
То же зарезервированное слово для определения сущности "instrument" - в текстовом редакторе вводится за 1.5-2 секунды (кото-то и быстрее введёт, я уж не говорю о шаблонах и копипасте, и быстрых подсказках ввода) - ошибка в тестовых процессорах будет видна сразу (это же ключевое слово - оно не будет выделено соответствующим образом) - и на её осознание и исправление (требующееся очень редко) уйдёт ещё секунды 2-3.
А сколько времени уйдёт в визуальном редакторе размещение такого компонента на поле (так оставим в стороне вспомогательные средства быстрого ввода): надо где-то нажать кнопку с командой добавления компонента, затем выбрать его из списка, или воспользоваться текстовым поиском, кликнуть по кнопке добавления, перенести его в нужное место на плоскости (а то ещё и другие компоненты подёргать) - это десятки секунд.... а потом окажется что это не тот компонент, что нужен (например, промахнулись - не туда кликнули)...
То же и про пропущенную кавычку - обычно это всё легко видно - небольшие сложности только в интерполяционных строках бывают - но были бы такие у Вас - были бы такие же проблемы, скорее всего - но это всё мелкие проблемы - и быстро исправляются.
P.S.
Вот опечатка с MIDI там где нужна WAVE именно в моём ЯП всплыла- бы только при компиляции - когда драйвер устройства WASAPI не смог бы по типам данных спрячься с типом данных, передаваемых из канала! Но это уже нюансы ЯП гибкой статической типизации - точные типы появляются только при компиляции!
Упущенный параметр "Input=InputChanel2" для "Track2" (без специально настроенных анализаторов) всплыл бы только при отладке - параметр не обязательный (как и то, что у трека может не быть входного канала данных - когда он сами их статически описывает или генерирует, или откуда-то загружает) в своём теле - внутри { }; или в трек могут напрямую отправляться инструкции из другого трека (трек сначала может динамически наполняться, а потом только воспроизводиться, или не обязательно воспроизводиться, а, скажем, выгружаться на диск в файл/БД, или передаваться в другую программу, в т.ч. по сети)!
Пропущенное указание треков, которые надо стартовать при старте проекта - это скорее нюансы дизайна ЯП - может действительно не надо стартовать никаких треков - а при старте проекта нужно выполнить сначала подготовительные алгоритмы... но можно, конечно ввести какую-то конструкцию - указывающую на это - и когда ничего нет - хотя бы выдавать предупреждение при компиляции
Скажу так - в этом конкретном случае лишь три проблемы:
Отсутствие правильно архитектурно подготовленных библиотек и документации к ним
Отсутствие настроенных кодогенератор, отладчиков и прочего суппорт-софта для данной среды
Закостенелость мышления технического руководства
Я же выше написал - что системное программирование ещё долго будет с нами - и там будет править классика. Но, объёмы такого программирования будут год от года снижаться. А вот объёмы кодогенерации, в т.ч. и в области системного программирования будут год от года расти. А визуальное и декларативное программирование будут как раз стоять на фундаменте низкоуровневой кодогенерации и некоторых системных готовых библиотеках!
Я ни разу не говорил, что Ваше решение - не рабочее и не может иметь практической ценности или быть популярным в определённых кругах. А так да - только практическое применение и отзывы могут показать эффективность того или иного подхода. У меня пока нет рабочего решения :-(
Про повторное использование кода, кодогенерацию и шаблоны, и разбиение по файлам/модулям - я уже написал выше. И уверен - даже незнакомые с построением DSP-плагинов люди, сходу поймут что да как тут происходит и настраивается! Не говоря уж про строки комментариев - и прочее самодокументированние!
Да и ЯП "Orange" - задуман как куда более мощная "штука", чем просто DSP-фильтр - так что тут есть "место" для боллеплейт-кода - но всё это можно вынести в повторноиспользуемый код -или применять шаблоны! Да и с некоторым "синтаксическим сахаром" это всё можно несколько было упростить - для простых случаев
P.S. Хотя компиляция проекта в DSP-фильтр или VST-плагин - тоже вполне возможна
Поспешил - ошибки допустил - что сам уже заметил:
Была проращена открывающая кавычка:
Driver = WASAPI("Динамики (Realtek High Definition Audio)"
Опечатка "instrumnet"->"instrument"
В обоих OutputChanel ошибочно указал формат MIDI - там, конечно же WAVE - но может быть и MIDI - но тогда VSTi семплер будет проигнорирован (если он не сможет выдавать MIDI поток)
В "Track2" забыл указать параметр "Input=InputChanel2" для настройки канала, по которому в трек будут поступать MIDI события!
При старте проекта хорошо было бы указать и стартуемые треки, ну или аннотировать их как автотстартуемые вместе с проектом (а вообще треки могу запускаться (и останавливаться) в произвольный момент времени - мануально, по расписанию, по событию и другими способами - тут полная гибкость):
run MyProject with track(Auto) [MyLayer.Track1, MyLayer.Track2]
У значений перечислений без указания полного пути идентификатора - по-хорошему надо бы поставить точку перед идентификатором значения - чтобы синтаксический разбор понимал, что надо проанализировать тип приёмника для идентификации полного имени значения - но, будем считать, что можно и без точки, когда нет пересечений идентификаторов в текущем контексте - опция настройки проекта)
Примечания:
Маппинг каналов скорее лучше делать через отдельный компонент Mixer - но для простоты не стал его указывать - а вообще - в мультиканальном проекте с пространственным 3D0звучанием такой компонент может активно применяться!
Вместо указания параметра инструмента "ProgramFIxed" (что скорее для инструментов, которые не поддерживают разные программы звучания) лучше настроить у InputChanel компонент фильтра - для отбрасывания MIDI инструкций смены инструмента:
Пример фильтрации в каналах
chanel InputChanel1
{
Direct = Input
Format = MIDI
Source = InputDevice1
Filter = MIDIBoolFilter
{
return MIDIEvent.Command != ProgramChange)
} //Задали произвольный алгоритм фильтра MIDI сообщений - пропускаются только "истинные" MIDI события
}
chanel InputChanel2
{
Direct = Input
Format = MIDI
Source = InputDevice2
Filter = MIDIEventFilter
{
return ? (MIDIEvent.Command == ProgramChange) MIDIEvent:new{Command=None}
} //Задали произвольный алгоритм фильтра MIDI сообщений - подменяющий сообщения по смене программы на пустую команду (в условии нет секции "иначе" - она генерируется автоматически - исходным значением событий); а, в принципе, такой фильтр может и другие преобразования делать (для WAVE-формата канала тоже свои фильтры могут быть - но там, их лучше подключать как DSP-процессоры - между каналами)
}
Filter = MIDIBoolFilter
{
return ? (MIDIEvent.Command==ProgramChange) MIDIEvent:{Command=None}
} //Задали произвольный алгоритм фильтра MIDI сообщений - подменяющий сообщения по смене программы на пустую команду (в условии нет секции "иначе" - она генерируется автоматически - исходным значением событий)
Музыкальный трек организован куда сложнее - чем показано в данном примере - он может обслуживать мульти-инструменты, мульти-эффекты, полифонию, мульти-семплирование, мульти-каналы и т.д. и т.п. По сути - трек - это просто некоторая агрегация сервиса воспроизведения (как и слой, как и, не указанный здесь, score - для разделения партитур) - все они определяют свой контекст воспроизведения
Я бы назвал это преимущество весьма сомнительным. Да - можно - но много ли от этого толку... а сколько это в итоге порождает проблем в сложных схемах... Насколько это поддаётся эффективной и продвинутой отладке... Насколько это всё само документируемо, и поддаётся созданию отдельной документации...
Поэтому в своё примере выше - у меня все узлы именованы (кроме узлов проекций/фильтров - это порты, принадлежащие своим узлам, но - в принципе им, как и линиям тоже можно было бы вешать лейблы)! А так - как, в другом комментарии выше, я показывал - можно и анонимную лямбду создать - и передать её в другой блок!
Да, при визуализации вполне допустимо - но, опять же, очень спорное решение - усложняет понимание схемы!
А насчёт примера.... ну я тут выше в комментарии уже приводил примеры своего ЯП для музыки "ORANGE" - он текстовый и на нём ваш пример (в котором, правда большая часть информации отсутствует в обоих вариантах представления) выглядел бы так:
пишу целиком, включая шапку, без особых синт. сокращений:
project MyProject
{
device OutputDevice1
{
Direct = Output //Не обязательно - т.к. это по умолчанию так
Format = MIDI
Driver = WASAPI(Динамики (Realtek High Definition Audio)"
ChanelsMap = {Left->"L", Right->"R", BackLeft->"BL", BackRight->"BR"}
}
device OutputDevice2
{
Direct = Output //Не обязательно - т.к. это по умолчанию так
Format = MIDI
Driver = WASAPIOut(
"LG ULTRAGEAR (Аудио Intel(R) для дисплеев)")
ChanelsMap = {Left->"L", Right->"R"} //Не обязательно - т.к. это по умолчанию так (когда у устройства нет других каналов)}
device InputDevice1
{
Direct = Input
Format = MIDI
RAWFormat = Int
RAWConverter = System.Converters.ToMIDI.KeyboardScanCodeToMIDI Driver = KeyboardInput //Если я правильно понял – что источников является букво-цифровая клавиатура
RAWInternalConverter += @AnotherFunction //Если нужен какой-то свой обработчик конвертации потока кодов клавиатуры в MIDI инструкции
ChanelsMap = {Mono->"1"}
}
device InputDevice2
{
Direct = Input
Format = MIDI
Driver = MIDIInput("LoopBe Intenral") //Какой-то MIDI input - из примера не ясно как он настроен
ChanelsMap = {Mono->"1"}
}
chanel OutputChanel1
{
Direct = Output //Не обязательно - т.к. это по умолчанию так
Format = MIDI
Space = STEREO //Не обязательно - т.к. это по умолчанию так
Destination = OutputDevice1
ChanelsMap = {Left->Left, Right->Right} //Маппинг только в два канала устройства воспроизведения
}
chanel OutputChanel2
{
Format = MIDI
Destination = OutputDevice2
//ChanelsMap = {Left->Left, Right->Right} //Не требуется, т.к. тут маппинг по умолчанию в два доступных у устройства канала
}
chanel InputChanel1
{
Direct = Input
Format = MIDI
Source = InputDevice1
}
chanel InputChanel2
{
Direct = Input
Format = MIDI
Source = InputDevice2
}
sampler S_yxg50_Sampler
{
Format = VSTi
Path = FilePath("c:\vst\yamaha\syxg50.dll":raw)
Space = STEREO //Не обязательно - т.к. это по умолчанию так
ChanelsMap = {Left->"01", Right->"02"}
}
instrument S_yxg50
{
Destination = S_yxg50_Sampler
Program = 8 //Вообще инструмент подразумевает фиксацию программы синтезатора здесь (т.к. именно инструмент определяет настройки звучания), но в примере она фиксируется только для одного Midi input (вероятно у другого - другая программа) - такое тоже возможно (здесь только значение по умолчанию)
}
layer MainLayer
{
track Track1
{
use instrumnet S_yxg50(ProgramFixed=true)
use input InputChanel1
use output [OutputChanel1,OutputChanel2] //В моей схеме не семплер подключается к каналам вывода, а музыкальный трек (здесь подключение сразу к двум каналам
runtime input:loop //трек активен только в runtime режиме в бесконечном цикле воспроизведения
}
track Track2
(
Instrumnet=S_yxg50(Program=3, ProgramFixed=true) //Сменили программу (тут будет клон инструмента)
Output = [OutputChanel1,OutputChanel2]
) @RuntimeInput(lnfinity) //аннотация режима исполнения трека
}
Layers=[MainLayer]
}
run MyProject
Надеюсь ничего не забыл, и правильно понял исходный пример. Да - может код несколько многословен - но тут много базового конфигурирования идёт. У Вас же, в визуальной части, настройки делаются в узлах - и не отображаются, но их всё-равно надо делать (текст тоже можно скрыть в сворачиваемых блоках, распихать по файлам и подключаемым модулям библиотек, в т.ч. для повторного использования), ну и текст легко комплексно просматривается, и легко рефакторится, и легко публикуется и передаётся куда-либо, да хоnть в Git
И да - всё-таки ЯП ORANGE хоть и спроектирован для реализации runtime MIDI-ввода - но, всё же, создан больше для кодирования воспроизведения в виде инструкций к семплерам (что можно делать и в runtime; или направлять MIDI инструкции из источника в генератор кода в инструкциях ЯП Orange)!
Ну - для этого возможны:
Шаблоны быстрого ввода в текстовом процессоре IDE (в т.ч. привязанные к macros и static instument generators, которые могут читать конфигурацию из внешнего config-файла, а так же иметь доступ к AST-дереву выражений проекта - чтобы генерировать код максимально гибко и адаптивно; но я не говорю - что такое в принципе нельзя сделать при визуальной разработке - но инструментарий IDE должен быть очень продвинутым, в отличии от текстовых процессоров - где это либо уже реализовано, либо легко подключается плагинами, либо вообще решается на уровне компилятора и/или внешнего текстового препроцессора)
Просто готовые преданстроенные функции внутри проекта или во модулях библиотек - которые просто можно вызвать (в т.ч. с параметрами) - а они уже проведут всю общую настройку - в этом преимущество классического подхода кодирования исходников - в гибком повторном использовании кода (но я не говорю - что такое в принципе нельзя сделать при визуальной разработке)
del
Есть одно пересечение от функции "Process" к "B" (в идеале там должно быть "мостик" - рисовал в ""Miro" - не поддерживает, видимо) - но, замечу, что как раз в этой схеме его можно избежать, нарисовав линию стрелки в другую сторону (обогнув функцию "Process2")! Кстати, IDE может иметь средство перераспределения схемы/части схемы - для минимизации пересечений.
В более сложных схемах могут применяться разные способы избежание пересечений или решения проблем их читаемости. Например, можно клонировать состояние системы в узле "А" (переменной/источнике/примёнике) - и нарисовать его ниже отдельно - так чтобы его связи не мешали другим. Или размещать их на разных слоях (в т.ч. с настроенной прозрачностью или цветами линий - чтобы даже в неотображаемом или полуотображаемом случае видеть намёки, что тут есть и другие связи). Можно и сами линии группировать через промежуточные узлы - и начинать из них движения тоже где-то ниже. Можно просто часть линий выносить в узел субпрограммы, который в основном режиме отображается как просто узел, а при детализации (как написал выше - это легко делать просто масштабированием схемы, ну или просто кликом по лупе в этом узле) - уже отображать отдельно его структуру. И так далее и тому подобное - вариантов как синтаксических так и средств IDE может быть много! Не думаю, что это такая уж проблема. Тем более, что я, ту не требую целостности графа, а в большинстве случаев такого большого числа переходов из одного узла вряд ли будет - на картинке уж очень специфическая ситуация - чаще всего инструкции достаточно линейны (ветвления условий и матчей - скорее всего не будут шибко обширными или хорошо сворачиваются, по указанным выше, или иным, методикам), а распараллеливания - вполне можно достаточно эффективно разнести друг от друга.
Кстати, IDE может даже представлять схему в разных вариантах компоновки - просто меняя способы её отображения (фактически не переставляя сами элементы) - что позволяет легко подстраивать её анализ под разные ситуации
У визуального программирования есть пара интересных архитектурных преимуществ - перед текстовым:
Очень удобно управлять множественными потоками данных - в т.ч. ветвлениями или дублированием (см. пример ниже). От одного источника легко может исходить несколько переходов. И на эти переходы можно удобно накалывать разные условия или метки аннотаций - задающие логику работы. Более того, на источник и на приёмник можно вешать как бы специальные порты - проекции/фильтрации - так что все исходящие или, соответственно, входящие линии переходов, из/в эти порты, будут подвержены зависимы от действий, заданных в этих портах - и на один источник/приёмник можно повесить сразу несколько разных портов! Так же, множественные переходы могут удобно определять и параллельное выполнение этих операций (в т.ч. в режиме по умолчанию, когда компилятор сам решает как лучше выполнять эти действия - в отдельном потоке или последовательно - в зависимости от настроек контекста выполнения и специальных хинтов-аннотаций со стороны программиста)
В отличии от представления инструкций/деклараций в текстов - которых по сути линейны - графические схемы размещаются на плоскости - а, в принципе, в 3D и даже в большем числе измерений - что позволяет более наглядно размещать связи между элементами и вложенные блоки. Тут же можно сказать и про уровень масштабирования - когда можно приближая масштаб легко переходить от общего узла некоторого блока - к его внутренней реализации, оставаясь в текущем контексте, что позволяет (при необходимости), например, вместо внутренней логики подпрограммы (читай функции) подставлять идентификаторы текущего контекста - чтобы лучше понимать как внешняя среда влияет на результат внутренней
В схеме выше много действий. Условно начало можно считать получение фильтра FilterList (хотел сначала сделать точку входа Request - но передумал - и так сложно вышло)
Ключевым тут является источник переменной "A" (тип который является перечислимым) - у неё есть ряд исходящих портов разного типа - какие-то передают все данные переменной "A" (но только если сущность переменной "A" удовлетворяет условиям); какие-то передают только часть её содержимого - поэлементно удовлетворяющие условию. Так же тут осуществляются операции фильтрации данных по типам и контрактам (забыл добавить и просто операции преобразования)
Есть даже паттерн переназначения фильтра по умолчанию (он не изменяет передачу типа данных, но все условия на него, накладывается согласно заданного шаблона)
Короче - схема, безусловно очень абстрактная, но я просто хотел показать возможную глубину фишек визуального программирования на графических схемах
Кто его знает - сейчас трудно дать чёткую оценку тому, как будут программировать роботов лет через 100-200
Но Вы учтите - что лет за 100 и текущее - текстовое программирование в своей массе тоже сильно видоизменится! Как это уже происходило - пару раз - сначала переходом от перфокарт/перфолент как раз так и к примитивному текстовому вводу инструкций (от ассемблера до С++ и далее)- а затем второй раз - к более абстрактному программированию намерений (от Lisp/Prolog до SQL/NoSQL и далее). А современные ЯП - это скорее уж химеры, сочетающие стороны обоих подходов! Но я верю в то, что большая часть прикладного программирования будет всё больше уходить в обобщённое абстрактное программирование - в декларативной форме... такое, что гуру ЭВМ прошлого века точно бы не назвали классическим программированием - а уж противников, считающих, такой подход извращённым есть сейчас и будет через сотни лет - ещё вполне много - системное программирование навряд ли далеко уйдёт за ближайшие лет сто от прямых инструкций... Но роботов явно не будут программировать ни дома ни на "заводе" прямыми инструкциями - так что ЯП для них, что примышлённый, что домашний - вряд ли будут сильно отличаться по своим возможностям (но доступ к библиотекам и доступ к данным настроек - конечно будет различный, как и сложность этих библиотек и настроек - как это есть и сейчас - не всем дано ковыряться в недрах ядра ОС или БИОС, или даже системном меню бытовой техники)!
Кстати, восприятие визуального программирования, так сказать, массами может очень сильно измениться в ближайшие полвека. Если ещё лет десять-двадцать назад в школах программирование учили вяло и именно на классике - т.е. текстом. То сейчас ситуация сильно меняется - в школах активно начинают изучить программирование именно с графических систем, специально созданных для детей - типа Scratch - и это правильно - и это будет закладывать совсем иное и углублённое отношение к визуальным ЯП среди новых поколения - и чем больше будут уделать внимания разным графическим системам именно со школьной скамьи - тем ярче будет желание (как и не желание) - программировать и во взрослой жизни с применением визуальных сред. Но тут уже как душа у кого ляжет - но, всё-таки, некоторое привыкание к визуальному программированию будет с детства, а не так как у большинства нынешних уже состоявшихся программистов - которые хорошо освоили текстовый подход - и смотрят на иные средства как на что-то чужеродно!
Да и сами визуальные ЯП за ближайшие десятилетия, а то и столетие - подтянутся - и будут ещё более удобными, приятными и мощными в использовании - чем текстовая классика - но вряд ли они смогут вытеснить текстовый подход - скорее они его дополнят!
Мне кажется до домохозяек тоже это дойдёт - и тому будут две причины:
Продвинутые специализированные фреймворки "для чайников" + AI ассистенты + графическая визуализация (да хоть структурированная, да хоть по частям) дадут колоссальную поддержку в формировании программного кода
Людям придётся осваивать и программирование роботов так же как и когда-то пришлось осваивать бытовую технику, смартфоны и домашние компьютеры + я считаю, что повысится и уровень образовательной программы, подстраивающийся под реалии прогресса и быт, требующий более сложных знаний + будет совершенствоваться и автоматизироваться, и, в то же время, образовательная программа и средства обучения - дети уже с детского сада будут окружены цифровыми технологиями и индивидуальным подходом - думаю, что, и итоге, сам термин "домохозяйка" в текущем, чаще негативном интеллектуальном окрасе, уйдёт в прошлое - общий уровень повысится....
но.... безусловно, возможен и обратный процесс (и он весьма вероятен) - когда всеобщая автоматизация наоборот будет отталкивать людей от самосовершенствования и развития - всё больше направляю их по деградационной шкале к уровню животных - которым и корм дадут, и лоток уберут, и на прогулку выведут, и развлекут...
Но я не верю в долгое нахождение в промежуточном состоянии развития - оно не устойчиво - ведомое AI и тотальной автоматизацией человечество пойдёт в своём развитии либо в верх либо вниз (но возможны и периодические колебания - с длительными циклами нахождения в том или ином состоянии - тут многое зависит от того - как с таким человечеством справится этот самый AI - сумеет о его сохранить и направить на путь развития - или сочтёт это дело бессмысленным)!
Но всё это, на мой взгляд, ещё очень не скоро ждёт человечество - и деградация, и домашнее повсеместное программирование роботов, да и сами повсеместно распространённые роботы и продвинутый ИИ - я думаю от этого нас ещё отделяют столетия развития технологий....если за это время человечество не умудрится и без ИИ отправить себя в каменный век!
Но... тем не менее.... домашние программируемые роботы появятся, скорее всего уже во второй половине XXI века, пусть и с примитивным AI
Но программировать роботов на бытовом уровне, всё-таки, будет проще голосом - но на телевизоре/планшете может выводиться какая-то вспомогательная графическая информация