Комментарии 43
Не откроет. Думаете, вы первый? Таких идей уже было миллион. В лучшем случае из них как-то работает и не умерло — от силы процентов 5. Почему? Да потому что у этой идеи есть куча очевидных и менее очевидных недостатков. Например, самый очевидный — раз код не текст, значит вам не годятся все те инструменты, которые были сделаны человечеством для текстов, включая программистские типа diff, например. Значит вам придется сделать свое версионирование, допустим.
Ну т.е. не то чтобы идея вообще барахло, но реально она применима лишь в некоторых нишевых случаях. Как универсальное средство разработки пожалуй что ни разу не взлетело.
А самое главное — вы пытаетесь решать несуществующие проблемы. Или несущественные. Отличия в синтаксисе языка? Это такая неважная хрень. Я обычно пишу в одном проекте примерно на 4-5 языках, и у них у всех разный синтаксис в вашем смысле. Не напрягает ну совсем, для этого как раз давно есть текстовые редакторы и IDE.
Скорость разработки, путем подстановки цикла одной кнопкой? Ой, откройте для себя скажем IDEA, там это есть года так с 2005, не позже. Для Java, и других языков тоже. И да, сюрприз — если бы в жизни скорость разработки ограничивалась только этим…
Во вторых есть ещё одна хорошая возможность в том случае если программа выполняется в первом режиме. Можно построить речевой анализатор, который будет распознавать речевые команды, отдаваемые человеком и на их основе изменять устроение программы. Можно было бы отдавать команды вроде «Создай новое окно», «Когда нажимают на эту кнопку отправляй почту по адресу» или чего посложнее (в зависимости от развитости этого анализатора). И эта суб-программа вносила бы изменения в разрабатываемую программу. Во многих случаях речевое взаимодействие было бы очень полезно. Сказать что-то в микрофон зачастую гораздо быстрее чем использовать мышь с клавиатурой, к тому же это избавило бы от чтения многих страниц документации.
Самая существенная решаемая проблема — это длительная компиляция программ на текстовых языках.
… ну вот на C#, например. Длительная?
Можно построить речевой анализатор, который будет распознавать речевые команды, отдаваемые человеком и на их основе изменять устроение программы.
А что мешает сделать это с "традиционным" языком программирования?
Подскажите, сколько времени происходит компиляция программы на питоне? Или на js?
А как насчет instant run в Android с компилируемой джавой?
Весьма интересная идея, если я ее правильно понял… можно писать на нескольких языках одновременно… нужно переварить.
описанный способ программирования откроет огромные возможности
Действительно, как говорит sshikov, таких «конструкторов» существует очень много.
Если бы вы начинали с этих конструкторов, то осознали бы, что идея написания кода — это эволюция, логическое продолжение идеи компоновки блоков.
Когда вы попробуете написать действительно полезную, важную, большую программу на блоках, все описанные «плюсы» начнут вам только мешать.
- Синтаксиса не будет, но возникнет проблема выбора блоков из аналогов, их совместимости и прочего, что вы можете наблюдать в npm.
- В реальности, написать пару скобок, даже не смотря на клавиатуру, гораздо быстрее, чем найти нужный блок в каталоге, перетащить его мышкой и соединить с другими блоками. Учтите, что таких блоков очень много.
- Ну это вообще бред. Если только вы не продаете вместо готовых программ их исходники в магазине, то язык программирования влияет. Кроме того, имеет смысл передавать не код, а алгоритм.
- Тут вы совсем забыли про компиляторы, библиотеки, автоматическое форматирование и оптимизацию.
- Представление никак не зависит от кода/блоков. Составьте дерево синтаксическое/вызовов/иерархий и рисуйте его в виде комнаты. Но, важно заметить, что самый эффективный способ программирования — однонаправленный однопоточный непрерывный ввод символов с клавиатуры. Просто потому, что создаётся рефлекс, и вам уже не требуется обращать внимание на клавиатуру или набранный код.
Вот тут человек уже много лет продвигает похожую идею, правда на основе бинарной совместимости блоков, и даже разработал среду разработки, которая работает по такому принципу:
http://алексейнедоря.рф
Потому что современные языки программирования именно и работают с блоками. Пакеты, библиотеки, фреймворки, ООП это всё именно и есть тот набор блоков из которых мы и собираем программы. При этом можно в любой момент взять и немного изменить блок под себя не переступая через барьер.
Во-первых, мы избавимся от несущественных отличий в синтаксисе различных языков.
Языки отличаются не только синтаксисом, но и семантикой. for
в С++ — не то же самое, что for
в паскале, scala или питоне. Если избавиться от отличий, получится весьма невыразительный язык.
Во-вторых, увеличится скорость написания программы. Сейчас для того, чтобы написать оператор for в С-подобном языке нам нужно написать сам текст for, затем скобки, параметры, точки с запятыми, фигурные скобки, и нажать клавишу ввод.
Для программирования нет ничего быстрее при записи и нагляднее при чтении, чем текст. Графические инструменты (например, scratch, и даже мёртвый ДРАКОН ) уже существуют, но медленны и годятся только для простых программ.
А всё потому, что сложность языка программирования мала в сравнении со сложностью программы. Языки программирования просты. Для программиста не составляет труда помнить десяток синтаксисов различных языков. А вот структуру типичной программы из миллионов строк не запомнишь, и поэтому приходится часто читать код, читать много кода. И тут текст оказывается более компактным, гибким, удобочитемым, чем существующие графические представления кода.
В-пятых представлять структуру программы можно будет любым удобным для того способом. Например, в виде трехмерной комнаты, по которой можно перемещаться наподобие компьютерных игр и редактировать связи трехмерных классов и объектов.
Будет ли это удобнее? Может быть, вместо UML диаграмм пакетов/классов/объектов трёхмерная комната будет выглядеть нагляднее. Но, имхо, не вместо for'ов и while'ов внутри функции.
P.S. И как вы представите в одинаковых графических блоках C++ и Хаскель?
| уже существуют, но медленны и годятся только для простых программ.
Не совсем мёртвый, и есть определённая изюминка его использования в общем процессе разработки программ. :)
Пример темы на форуме Дракон языка Преимущества языка ДРАКОН для деревьев принятия решений (код может генерироваться на разные языки программирования)
Довольно малоприменимый подход.
Получится своего рода код, который генерируют визуальные редакторы html, с поправкой на то, что языков программирования много и они намного сложнее и богаче в синтаксисе и возможностях. О качестве генерируемого кода можно даже не говорить.
Такой подход имеет право на существование в очень ограниченном списке задач. Но зачастую это проще и лучше обойти встроенным рантаймом иного языка. Например, встраивание lua в язык более низкого уровня.
И еще: только не примите, пожалуйста, в свой адрес, поскольку вольная ассоциация.
В самом начале нулевых одна моя знакомая очень, очень ждала двух вещей. Хороших автопереводчиков, ибо не хотела учить английский, и хорошую распознавалку речи, ибо не хотела учиться печатать. Ей же было уже тридцать пять, жизнь практически позади и все эти технические подробности на самом деле нужны только затем, чтобы подвести некоторые итоги в этой самой уже прошедшей жизни.
Ждет до сих пор.
Кнопочки работали, но чтобы они что-то делали, это что-то нужно было прописать унылым текстом. Сама по себе кнопочка могла нажиматься, отжиматься и отлавливать это состояние. А привязать к нажатию какой-нибудь там выход из программы надо было уже вручную.
Или я что путаю?
Так что не в кнопочках дело. :-)
Вот только, как оказалось, по одной и той же структуре данных можно сгенерировать дофига разных программ...
Если я вас верно понял, то собственно там, где требовалась логика посложнее и гибкости побольше, он также оказывался неприменим?
Просто если нужно было совсем не стандартное, то надо было писать код, как обычно.
Например мой коллега писал программу, для приема документов в ВУЗ.
Быстро накидал прототип с отчетами. А потом ручками дописывал кучу ФЛК, чтобы операторы не могли ввести фигню.
если нужно было совсем не стандартное, то надо было писать код, как обычно.Да, я это и имел в виду.
Самые базовые вещи автоматизируются, и могут быть представлены графически. Но шаг влево, шаг вправо, и от написания кода руками деться некуда. Собственно, это была моя основная мысль с первого коммента начиная, но похоже, я в этом треде несколько косноязычен.
Для этого в первую очередь нам потребуется хранить исходные коды в другой форме.
… ну то есть хранить сериализованное синтаксическое дерево.
Например, блоки кода в С++ разделяются фигурными скобками, а Ruby обращает внимание на ключевые слова… В редакторе можно настроить и тот и другой вид программы, от этого не поменяется ничего в ней самой. Персональные настройки отображения позволят разработчику смотреть на программу так, как ему нравится. Кроме того, мы сможем использовать любые символы при именовании, включая пробелы.
Как вы думаете, почему этого до сих пор не сделано? Помимо многих других ответов, есть один очень простой: производительность. Как вы ни старайтесь, обычный текстовый редактор вы не обгоните.
Сейчас для того, чтобы написать оператор for в С-подобном языке нам нужно написать сам текст for, затем скобки, параметры, точки с запятыми, фигурные скобки, и нажать клавишу ввод. В нашем же варианте среда программирования по нажатию на определенное сочетание клавиш вставит цикл и потребует только ввести его параметры. Например, по нажатию на «f» поставит на место курсора цикл for и предложит ввести количество повторений и название счётчика через табуляцию, нажав клавишу ввод в конце
Вы про сниппеты никогда не слышали?
В-третьих, можно будет обеспечить независимость от языка программиста.[...] Насчёт имён объектов и методов посложнее, но в любом случае, если программа разрабатывается русскими разработчиками
А с многоязычными командами разработки что делать? А с тем, что порядок слов в разных языках разный?
В-четвертых появится возможность обновления структуры программы.
Она и сейчас есть. Возьми исходники, разбери в дерево, обнови, сохрани обратно.
В-пятых представлять структуру программы можно будет любым удобным для того способом.
Она и сейчас есть. Возьми исходники, разбери в дерево, визуализируй как хочется.
В каком-то смысле, ваш подход (редактируй не то, что хранится в файле) напоминает миллион существующих визуальных редакторов (форм, веб-страниц, рабочих процессов, схем БД). И все равно люди, которым нужен контроль за происходящим, спускаются на уровень исходников, потому что визуальный редактор нужного контроля не дает. Так будет и у вас — в итоге вы сделаете еще один язык программирования, такой же, как другие, просто с визуальным редактором.
Blockly и Scratch хороши для детей/начинающих, т.к. внешняя простота достигается за счёт того, что ограничения универсальности спрятаны "под капотом". Импорт нужных модулей, например.
Делали программатор полётов для Bitcraze на Blockly.
Вот как выглядел оригинал на Питоне:
import logging
import sys
import time
import cflib.crtp
from cflib.crazyflie import Crazyflie
from cflib.crazyflie.syncCrazyflie import SyncCrazyflie
from cflib.positioning.motion_commander import MotionCommander
from cflib.utils.multiranger import Multiranger
URI = 'radio://0/80/2M'
if len(sys.argv) > 1:
URI = sys.argv[1]
# Only output errors from the logging framework
logging.basicConfig(level=logging.ERROR)
def is_close(range):
MIN_DISTANCE = 0.2 # m
if range is None:
return False
else:
return range < MIN_DISTANCE
if __name__ == '__main__':
# Initialize the low-level drivers (don't list the debug drivers)
cflib.crtp.init_drivers(enable_debug_driver=False)
cf = Crazyflie(rw_cache='./cache')
with SyncCrazyflie(URI, cf=cf) as scf:
with MotionCommander(scf) as motion_commander:
with Multiranger(scf) as multi_ranger:
keep_flying = True
while keep_flying:
VELOCITY = 0.5
velocity_x = 0.0
velocity_y = 0.0
if is_close(multi_ranger.front):
velocity_x -= VELOCITY
if is_close(multi_ranger.back):
velocity_x += VELOCITY
if is_close(multi_ranger.left):
velocity_y -= VELOCITY
if is_close(multi_ranger.right):
velocity_y += VELOCITY
if is_close(multi_ranger.up):
keep_flying = False
motion_commander.start_linear_motion(
velocity_x, velocity_y, 0)
time.sleep(0.1)
print('Demo terminated!')
Вот как выглядит у нас на Блокли:
Летает одинаково, вот так:
Тем кто английского и Питона не знает — да, возможно, чуть понятнее. Но отладить что-то более сложное — это означает не просто отладить код, а ещё и устранить артефакты на этапе конвертации из Блокли в исполняемый код — ученикам это уже не под силу… Так что для начинающих изучать программирование — да, Scratch, но прикладные задачи решать — только разрабатывать такой Scratch для конкретной предметной области, целесообразность чего надо оценивать в каждом отдельном случае…
Ну а вообще по теме визуала более интересным выглядит что-то в стиле JetBrains MPS
www.youtube.com/watch?v=XolJx4GfMmg
Пожалуйста, представьте следующий алгоритм в виде блоков и потом на разных языках. Допустим, на хаскеле и си (или, если хотите, лиспе и паскале)
def filter_strings(data):
return [
x for x in data if isinstance(x, str)
]
data = '[1, 2, "hello"]'
smth = filter_strings(json.loads(data))
smth = list(filter(lambda x: isinstance(x, str), json.loads('[1, 2, "hello"]')))
А если по сути, то в вашем примере нет ничего такого кроме вызова готового модуля, встроенной функции и генератора списков.
Ваш код довольно-таки тривиально транслируется в цикл с if'ом. А могло быть и хуже:
object FormulaParser extends RegexParsers with PackratParsers {
def id: Parser[Id] = "[a-zA-Z][a-zA-Z0-9_]*".r ^^ Id
def number: Parser[Number] = "-" ~> number ^^ (n => Number(-n.value)) |
("[0-9]+\\.[0-9]*".r | "[0-9]+".r) ^^ (s => Number(s.toDouble))
def funcCall: Parser[FuncCall] = id ~ ("(" ~> expression <~ ")") ^^ {case id ~ exp => FuncCall(id, exp)}
def value: Parser[Expression] = number | funcCall | id | ("(" ~> expression <~ ")")
lazy val term: PackratParser[Expression] = term ~ ("*" | "/") ~ value ^^ binOperation | value
lazy val expression: PackratParser[Expression] = expression ~ ("+" | "-") ~ term ^^ binOperation | term
private def binOperation(p: Expression ~ String ~ Expression) = p match {
case e1 ~ op ~ e2 => BinOperation(e1, BinOperator(op), e2)
}
def apply(code: String): Either[ParserError, Expression] =
parse(expression, new PackratReader(new CharSequenceReader(code))) match {
case Success(result, next) => Right(result)
case NoSuccess(msg, next) => Left(ParserError(msg))
}
case class ParserError(msg: String)
}
sealed trait Expression
case class BinOperator(operator: String)
case class Number(value: Double) extends Expression
case class Id(name: String) extends Expression
case class BinOperation(left: Expression, op: BinOperator, right: Expression) extends Expression
case class FuncCall(funcName: Id, argument: Expression) extends Expression
object Evaluator {
def apply(expression: Expression,
variables: (String) => Double = Map.empty,
functions: (String) => (Double) => Double = Map.empty): Double = {
def eval(exp: Expression) = this (exp, variables, functions)
expression match {
case Number(value) => value
case Id(name) => variables(name)
case BinOperation(left, op, right) => operator2func(op)(eval(left), eval(right))
case FuncCall(funcId, expr) => functions(funcId.name)(eval(expr))
}
}
def operator2func(binOperator: BinOperator): (Double, Double) => Double =
binOperator.operator match {
case "+" => (a, b) => a + b
case "-" => (a, b) => a - b
case "*" => (a, b) => a * b
case "/" => (a, b) => a / b
}
}
object Main extends App {
def eval(code: String,
variables: (String) => Double = Map.empty,
functions: (String) => (Double) => Double = Map.empty) = {
val parsed = FormulaParser(code)
parsed.left.foreach(error => println(s"\'$code\' parsing error: $error"))
parsed.right.map(expr => Evaluator(expr, variables, functions)).foreach(d => println(s"\'$code\' = $d"))
}
eval("1")
eval("0.1")
eval("1.")
eval(" 1 ")
eval("-0.1")
eval("1+2")
eval("2-1")
eval("2*3")
eval("4/2")
val vars = Map(
"pi" -> math.Pi,
"e" -> math.E)
val funcs: (String) => (Double) => Double = Map(
"sin" -> math.sin,
"cos" -> math.cos,
"inc" -> { d: Double => d + 1 }
)
eval("pi", vars)
eval("inc(e)", vars, funcs)
eval("2+2*2")
eval("1+2*(3+4*5)")
eval("8/2/2")
eval("8-1-2")
eval("1. + 2.0 * sin(pi / 2)", vars, funcs)
}
(взято отсюда)
При желании, наверно, тоже можно транслировать в блоки, но если такого кода десятки тысяч строк — текст будет занимать намного меньше места.
Но с другой стороны, блоки — тоже DSL, только графический, а не текстовый.
Ваш код довольно-таки тривиально транслируется в цикл с if'ом.
Это пока в целевом языке есть возможность определить тип объекта во время выполнения.
(я тоже с первого раза не заметил, в чем дело)
Проблема в том что ТС во первых решает проблему которой нет, второе ТС не особо понимает почему же кроме различий в синтаксисе есть разные языки и почему тот или иной используется в той или иной сфере.
Собственно нет ни какой проблемы реализовать это же в «блоках» если будет такой функционал.
Ну то есть фактически понадобится написать для каждого языка свою собственную дополнительную "стандартную" библиотеку, чтобы покрыть такую функциональность.
Объем работы — это тоже проблема.
А свою стандартную библиотеку для всех языков не обязательно писать, скорей всего придётся делать свой интерпретатор с преферансом и девушками лёгкого поведения, а если опираться на существующие языки, то можно выбирать язык в зависимости от необходимых фич, и просто обеспечить согласованность работы и передачи данных между блоками. Как ТС это собирается это сделать у него уже спрашивали.
Конечно можно написать и интерпретатор для каждого языка, но сути это не меняет. Производительности таким образом теоретически можно добитться большей, но сложность реализации на порядок возрастет, на мой взгляд.
Причем не умозрительные рассуждения, а опыт трех лет практической работы с подобным «конструктором Лего» (конкретно — с Intershop Enfinity Suite). И я скажу так — это худшее, что со мной случалось за весь мой 25-летний стаж работы программистом.
Хорошего можно сказать только одно — это красиво выглядит. ВСЕ!
Дальше идут только одни проблемы:
— передача данных между блоками. Реализована в виде банального dictionary — то есть прощай типизация. Чтобы понять, что идет на выход из одного блока, и что идет на вход другого — изучай properties каждого блока. Отдельный привет, если данные не совпадают по формату — приходится лепить промежуточный блок для конвертации. А теперь мысленно представьте, какую площадь занимает Map<ID, List> -> List. То, что на чистой джаве укладывается в пять строчек, занимает пол-экрана.
— найти нужный блок. Медитируешь, пытаясь понять, какой из 20 блоков xxxPricexxx тебе нужен — а в итоге выясняется, что нужен какой-нибудь applyVAT
— громоздкость. Отлично, когда диаграмма простенькая, линейная и укладывается в в один экран. Но, с более-менее сложной логикой… это постоянный скроллинг в стороны, изменения масштаба и прочие удовольствия.
— ну, и least but not the last — code merge. Это просто аццкий сотона в кубе! Какие-то конфликты сложнее «добавить один блок посередине» можно решить, только очищая диаграмму, а потом ручками накатывая на нее блоки. Иначе либо отказ в автоматическом мерже (в лучшем случае), либо абсолютная каша из двух веток с совершенно рандомными переходами.
Можно было бы вспомнить еще — но и этого более чем достаточно, чтобы сделать вывод: идея красивая и наглядная, но в реальной разработке совершенно негодная.
Повторюсь еще раз — это не теоретические мысли, это опыт практического использования такой системы во вполне реальных проектах. Упаси Боже от таких «улучшений»!
Идея великолепная. Но не для разработки в деле, а для обучения. После того, как на всех углах детишек учат в Scratch -- как им показать что-то принципиально отличное?!
Блочное представление программы -- лишь часть задачи. Нужно графическое представление пространства задачи.
Блочное программирование