Поиски «идеального» GUI. Путь новичка

    Изучая первый язык я хотел видеть кнопочки, а не только текст в консоли. Я сделал на Python3+tkinter калькулятор. Это заняло 585 строк. Применив к коду магию py2app, я получил bundle размером 45MB. Мне не понравилась работать с py2app. Иногда все переставало работать, если использовались сторонние библиотеки, а иногда я исправлял код py2app. Из-за этого я думал, что standalone-приложения делать очень сложно.


    Через год я познакомился с xCode и калькулятор для iOS занял всего 125 строк. Нужно учитывать, что кнопки были сделаны в визуальном редакторе, а из операций я оставил только: «+», «-», «*», «/». Bundle получился меньше 10 MB.


    Пару недель назад я нашел способ сделать калькулятор для Mac OS без xCode. У меня получилось уложиться в 57 строк и я перестал бояться Swift.

    import AppKit
    let winWid: CGFloat = 256
    let wihHei: CGFloat = 180
    let dispHei: CGFloat = 18
    let rows = 4
    let rowHei: CGFloat = 32
    class AppDelegate: NSObject, NSApplicationDelegate {
        lazy var window = NSWindow(contentRect: NSMakeRect(0, 0, winWid, wihHei),
                                   styleMask: [.titled, .closable], backing: .buffered,
                                   defer: false, screen: nil)
        let display = NSText(frame: NSMakeRect(0, wihHei - dispHei, winWid, dispHei))
        func applicationDidFinishLaunching(_ notification: Notification) {
            window.title = "Machine"
            window.contentView?.addSubview(display)
    
            let eq = NSButton(frame: NSMakeRect(0, 0, winWid, rowHei))
            eq.title = "="
            eq.target = self
            eq.action = #selector(eval)
            window.contentView?.addSubview(eq)
    
            let items = ["C","0",".","/","1","2","3","*",
                         "4","5","6","-","7","8","9","+"]
    
            let sz = CGSize(width: (winWid/CGFloat(rows)),
                            height: rowHei)
            for i in 0..<items.count {
                let x = i % rows
                let y = i / rows
                let b = NSButton(
                    frame: NSMakeRect(sz.width * CGFloat(x),
                                      sz.height * CGFloat(y) + rowHei,
                                      sz.width, sz.height))
                b.title = items[y*rows+x]
                b.target = self
                b.action = i==0 ? #selector(clear) : #selector(input)
                window.contentView?.addSubview(b)
            }
            window.makeKeyAndOrderFront(nil)
        }
        @objc func input(sender: NSButton) {display.string! += sender.title}
        @objc func eval(sender: NSButton) {
            let exp: NSExpression = NSExpression(format: display.string!)
            if let result: Double = exp.expressionValue(with: nil, context: nil) as? Double {
                display.string = String(result)
            }
        }
        @objc func clear(sender: NSButton) {display.string = ""}
        func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
            return true
        }
    }
    let delegate = AppDelegate()
    var appl: NSApplication
    #if swift(>=5.1)
        appl = NSApplication.shared
    #else
        appl = NSApplication.shared()
    #endif
    appl.setActivationPolicy(.regular)
    appl.delegate = delegate
    appl.run()
    

    Если сохранить код в main.swift и запустить в терминале команду:

    swiftc main.swift
    

    Мы получим бинарный файл, который можно упаковать в приложение или просто запустить в терминале. Калькулятор считает не совсем привычным образом. Кнопка "=" вычисляет все, что написано на дисплее.


    Но больше всего, меня обрадовал язык Red. Калькулятор на нем можно поместить в 13 строчек. А размер standalone приложения для MacOS будет всего 1 MB.

    Red [Needs: View]
    View [
        title "Red"
        disp: field 330x50 font-size 25 "" return
        style b: button 71x40 [append disp/text face/text]
        b "1" b "2" b "3" b " + " return
        b "4" b "5" b "6" b " - " return
        b "7" b "8" b "9" b " * " return
        b "0" b "." b " / " b " = " [attempt [
            result: form do disp/text
            append clear disp/text result]] return
        button "C" 325x40 [clear disp/text]
    ]
    

    Сохраняем код в main.red и набираем в консоли:

    red -t macOS main.red
    


    На сайте объявлено, что приложения можно собирать под Windows, Linux, MacOS и др платформы.
    Жаль, что разработчики языка пока не среагировали на то, что Apple не поддерживает 32-битные приложения после версии macOS 10.15

    Буду рад, если кто-нибудь подскажет более простые варианты создания GUI.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 157

      +2
      Kivy — питоновский фреймвок, в т.ч. для GUI. Можно собирать под основные десктопные и мобильные платформы.

      А вот здесь пример калькулятора.
      Два интересующих файла — Calculator.kv и main.py.
        0
        Спасибо, в 2017 меня остановила сложность установки фреймворка. Я посмотрю, вдруг сейчас все поменялось. А что кроме Kivy вы используете для Python GUI или графики?
          0
          Ну если не считать веб или какие-нибудь прикладные штуки типа matplotlib, то больше ничего.
            0

            Нашел у вас post про streamlit. На первый взгляд все супер, правда много библиотек надо установить. Спасибо.

        –14
        Буду рад, если кто-нибудь подскажет более простые варианты создания GUI.

        Пишем веб-интерфейс, а затем встраиваемый его в любое приложение на любой платформе на любом языке. Например, электрон, cef, Cordova.
          +18

          … и получаем калькулятор, тянущий за собой chromium и node.js и отжирающий чуть менее чем полгига RAM на ровном месте. Это из категории "вредные советы"?

            –3
            Не знаю, как у вас, а у меня 36 мб на голосовой чат (cefpython). Возможно, вам стоит прочитать про профайлер и заняться оптимизацией вашей половины гига.
              +4
              Я прямо сейчас вижу как, прямо скажем, не очень-то навороченный гуй Skype на электроне отжирает у меня на машине ~300Mb RAM. Возможно, вам стоит рассказать разработчикам из Microsoft про профайлер и все такое, а то они не знают, наверное.
                –8
                У меня всё хорошо.
                image
                Возможно, вам стоит рассказать разработчикам из Microsoft про профайлер и все такое, а то они не знают, наверное.

                Вы же страдаете, а не я. Никогда не задумывались, почему одно приложение потребляет 30 мб, а его аналог в 10 раз больше? Это как бы намекает на скрытые функции…
                  +2
                  Я не в курсе, что у вас там за приложение, и никогда его не видел, но вот все, что я видел из написанного на электроне (тот же новый скайп или дискорд) по какому-то странному совпадению является сильно охочим до ресурсов мусором. При этом я сильно сомневаюсь, что авторы этих приложений никогда не слышали про профайлер.
                    –1
                    Я вам про технологию, вы мне про реализацию. Я вам показал, что существует нормальная реализация, вы мне про электрон. Да, у электрона большой оверхед, это знает каждый второй. Но не я ведь его писал.
                      +1
                      Я пока так и не увидел нормальной реализации. Только услышал в вашем изложении. И то не про электрон конкретно.
                        –1
                        Предлагаю вам лично изучить этот вопрос, а не ждать лекции в комментариях. Начальный вектор я вам предоставил. Не хотите — жалуйтесь дальше.
                          +2

                          Предлагаю вам в следующий раз не трепать языком, а то опять получится "не Волгу, а велосипед, и не выиграл, а проиграл". Бремя доказательства утверждения всегда лежало на утверждающем.

                    0
                    это без браузера, а значит без CEF

                    впрочем, Process Explorer может доказать что я неправ
                      0
                      Это с браузером. Но вы в какой-то мере правы, т.к. process explorer показывает в 2 раза больше. Впрочем, 60 мб — всё-равно приемлемое число.
                        +1
                        Process Exprorer я предложил просмотреть список загруженных приложением DLL, чтобы понять, есть там браузер в адресном пр-ве или нет.
                          0
                          Я перепутал, у меня голосовой чат написан на pyWebView. Внутри он запускает clr, а в ней стандартный webview из wpf. Если не верите, посмотрите оф. сайт, но других связанных процессов я не смог найти.
                            +1
                            Глянул. Использует Microsoft.Toolkit.Forms.UI.Controls.WebView, который обертка над Edge.

                            Просто Edge потребляет (пока не перевели на Хромиум) меньше памяти чем Хромиум
                          0
                          Впрочем, 60 мб — всё-равно приемлемое число.

                          Для калькулятора?

                            0
                            Для голосового чата с шифрованием. Но, скорее всего, 50 мб является оверхедом (константой; для пустого проекта), а чисто приложение занимает всего 10 мб. Поэтому, когда приложение будет занимать 100 мб, то всего будет потребляться не 600 мб, а лишь 150 мб.
                              0

                              Так-то оно в общем и неплохо конечно, но если по гамбургскому счёту, это всё-таки раз так в 1000 больше вменяемой величины.

                      –7
                      С одной стороны я согласен с вами, что делать «калькулятор» на chromium и node.js это полный бред.

                      Но, с другой стороны, тот же дискорд, что вы упоминаете ниже, работает отлично и хороших кроссплатформенных аналогов фактически не имеет. И в 2019 жаловаться на обьем оперативной памяти это моветон. Этим летом я купил 64Gb оперативной памяти с частотой 3200 всего лишь за жалкие 200$.
                      Очень надоело это нытье из разряда «раньше было лучше, на моем нетбуке с xp-шечкой все шустро запускалось, и бравзер и ворд и винумп и даже видосики 720p!!!.. А вот сейчас веб макаки все испортили и моих ЦЕЛЫХ!!! 512mb уже не хватает!!!»

                      И оказывается что никому не интересно в текущих реалиях жрет приложение 300 или 500mb. Зато интересно другое, в случае того же слака или скайпа, и в ситуации когда девайса под рукой нет, есть гостевой комп и срочно нужно что-то порешать аж за океаном.
                      И последний момент. Не нравится — не пользуйся. Очень доставляет категория людей считающая что им все должны.
                        +2

                        Мне — интересно. Поэтому дискордом я не пользуюсь вовсе, а скайпом — только при очень большой необходимости, и то потому, что пара моих контактов другого способа оперативной связи не имеет. Рано или поздно откажусь и от него, так как считаю, что писателей откровенно плохо написанного софта поощрять не стоит. Эти "веб-макаки", как вы выражаетесь, в случае Скайпа даже не смогли толком воспроизвести уже имевшийся функционал из Скайп Классик, зато раздули потребление ресурсов сверх всякой меры. Это не тот путь, которым следует идти.

                          –1
                          Все имеет свои причины — я более чем уверен, что возможность повторить функционал старого скайпа была — но наверняка такая задача просто не ставилась.
                          Грубо говоря всем управляют «бабки», то есть запросы по функционалу неплатежеспособных (это даже не зависит от ваших реальных финансовых возможностей, а лишь от готовности тратить деньги) пользователей просто игнорируются. А платежеспособная часть просто может себе позволить более мощное железо. Именно по этой причине выпускают игры под новые консоли, а не под старые.
                          В целом я за сбалансированный подход. Специализированный и сложный софт должен быть нативным, быстрым и потреблять минимум ресурсов.
                          Остальной софт — выбор за пользователями и разработчиками. Если большинству выгоднее chromium — то почему нет?
                            +2

                            "Более мощное железо" потихоньку тоже перестаёт решать, производительность уже давно не удваивается каждые 18 месяцев. Скайп теряет рынок:


                            https://www.bloomberg.com/news/articles/2018-05-10/don-t-skype-me-how-microsoft-turned-consumers-against-a-beloved-brand


                            не в последнюю очередь из-за применения сомнительных технических решений, которые удобны для разработчиков, но не для пользователей.

                              –1
                              Да, железо тоже перестает решать. Вполне возможно будет обратная волна, когда софт будут оптимизировать и это будет экономически выгодно.

                              Скайп в основном же сожрали whatsapp, slack, viber и телеграмм. Так же сдох когда-то ICQ. Кстати ICQ работало даже на железе уровня микроволновки, но его это не спасло.
                              Кроме того компания, где я работаю, долго использовала Skype, но затем тоже перешла на Slack.
                                0

                                Да, но почему они его сожрали? Не потому ли, что MS тупо перестал прислушиваться к желаниям пользователей, а вместо этого начал ваять жручий, тормозной и малофункциональный мусор?

                                  –1
                                  Просто раньше Skype был по сути монополией, потом появились конкуренты и отхватили свою долю рынка.

                                  Насколько я знаю (могу ошибаться) Skype до сих пор очень популярен в латинской америке. Вот немного статистики по нему.
                              +2
                              А и еще. К сожалению HTML5 + CSS это лучшее что смог предложить рынок для десктопа по уровню функционал/документация/примеры. Если взять так любимый многими QT — профессионально и быстро выполнить сложный высер дизайнерской мысли смогут лишь полтора бородатых разработчика, в доках пока разберешься — тысячи Раджешей Кутрапале уже наваяют тоже самое на HTML5 + CSS и все — ты вне игры. Да, будет течь. Да, будет жрать. Но они заработали, а ты нет. Потому что ты все еще ищешь как без костылей сделать custom traffic lights titlebar на MacOSX.

                              Кстати кому интересно есть проект node + qt5 — тоже кроссплатформа, тоже Javascript, но без chromium.
                                0

                                Лично я считаю, что тот же QML сделан гораздо более пригодным для standalone приложений, чем html/css, которые изначально вообще для приложений как таковых не предназначались. Раджеши Кутрапале, конечно, наваяют вам ЧТО-ТО… Но как бы потом с этим "что-то" не получилось, как у MS со Скайпом. ИМХО использование вещей типа Электрона допускается только как временное решение — если нужно быстро сделать приложение на базе уже имеющегося веб-решения, это их ниша. Застолбить преимущество. Но затем с этого нужно уходить, а то юзеры проклянут, и уйдут к более оптимизированным конкурентам, а такие обязательно появятся.

                                  0
                                  А какое вы видите решение?
                                    0

                                    Лично я предпочитаю Qt. Я из тех самых "бородатых разработчиков", правда, бороды у меня все-таки нет :) Но тут есть нюанс — Qt — это все-таки для вещей посложнее калькулятора. Вот для таких, например:


                                    https://www.inobitec.ru/products/dicomviewer/


                                    Для калькулятора Qt все-таки жирноват.

                                      0
                                      Спасибо.
                                        +1

                                        Предупреждать же надо! Приложение, может, и хорошее, но я ослеп на первой же странице сайта. Белый текст на светло-голубых макаронах… я слишком стар для этого...

                                          0

                                          По мысли дизайнера, я так понимаю, это должны были быть сосуды, но это не точно.

                                          –1
                                          Наблюдаю у себя несколько лаунчеров от игр, сделаны на Qt+QtWebEngine. ИЧСХ частный рабочий набор тоже типично 80-90, и до 172Мб. Так что хрень редьки то…
                                            0

                                            С QtWebEngine — то неудивительно.

                                              0
                                              Вот такой куркулятор на QML:

                                              import QtQuick 2.12
                                              import QtQuick.Controls 2.12
                                              import QtQuick.Layouts 1.12
                                              import QtQuick.Window 2.12
                                              
                                              Window {
                                                  visible: true
                                                  width:   640
                                                  height:  480
                                                  title:   qsTr("Calculator")
                                              
                                                  ColumnLayout {
                                                      anchors.fill: parent
                                                      spacing:      16
                                              
                                                      TextField {
                                                          id:               textField
                                                          readOnly:         true
                                                          Layout.fillWidth: true
                                                          Layout.alignment: Qt.AlignVCenter
                                                      }
                                              
                                                      GridLayout {
                                                          rows:              4
                                                          columns:           4
                                                          Layout.fillWidth:  true
                                                          Layout.fillHeight: true
                                              
                                                          Repeater {
                                                              model: ["7", "8", "9", "+", "4", "5", "6", "-", "1", "2", "3", "*", "C", "0", "=", "/"]
                                              
                                                              Button {
                                                                  text:              modelData
                                                                  Layout.fillWidth:  true
                                                                  Layout.fillHeight: true
                                              
                                                                  onClicked: {
                                                                      if (text === "C") {
                                                                          textField.text = "";
                                                                      } else if (text === "=") {
                                                                          try {
                                                                              textField.text = evaluate(textField.text);
                                                                          } catch (e) {
                                                                              textField.text = e.message;
                                                                          }
                                                                      } else {
                                                                          textField.text = textField.text + text;
                                                                      }
                                                                  }
                                              
                                                                  function evaluate(expression) {
                                                                      return eval(expression);
                                                                  }
                                                              }
                                                          }
                                                      }
                                                  }
                                              }
                                              


                                              у меня кушает под виндой ~35Mb RAM, при этом просто пустой Window кушает столько же. Но, согласен, для куркулятора это тоже немало (к слову, штатный виндовый куркулятор кушает ~20Mb), поэтому я и написал выше про «жирноват». Но все же не 80-90. EXE занимает 28 килобайт, но не будем забывать про набор Qt'шных dll'ек, которые смело добавят еще метров 15 минимум. Хотя можно попробовать собрать статически, но возиться неохота — у меня Qt собран только в динамическом варианте.
                                                0

                                                Вместе с Qt я получаю QML и все необходимые библиотеки и если на MacOS собираю приложение, то оно работает для MacOS. Можно ли собрать приложение на MacOS для Windows/Linux?

                                                  0

                                                  Да, кросскомпиляция.

                                                    0

                                                    Кстати, у меня тут возник вопрос. Допустим, я делаю приложение под Linux и хочу распространять еще и бинари, чтобы упростить людям жизнь. Не получится ли так, что мне придется делать версию под каждую поддерживаемую версию каждого поддерживамаего дистрибутива, ведь там могут отличаться версии Qt и вся бинарная совместимость накроется?

                                                      0

                                                      Ну, есть варианты.


                                                      1. snap/flatpack всякие (но я их не использовал).
                                                      2. tar.gz со всеми нужными библиотеками и скриптом запуска, выставляющим нужный LD_LIBRARY_PATH. Я так делал на одной из прошлых работ, но там зависимостей было не так много, и гуёвых не было вообще. В гуях интеграцию с DE вы так, скорее всего, потеряете, если не озаботитесь этим отдельно, что может быть нетривиально.
                                                      3. Если это опенсорс, то забить и дать мейнтейнерам делать своё дело. Для своего креатива я выбрал этот подход.
                                                      4. У Qt есть какая-то бинарная совместимость вперёд, и вы теоретически можете собирать ваш софт, скажем, с Qt 5.8, и тогда он заведётся на любой машине, где Qt не старше 5.8, но есть нюансы, связанные с отсутствием у C++ ABI и того, что разные компиляторы могут манглить имена немножко по-разному.
                                                        0
                                                        В общем-то более новые версии Qt совместимы с более старыми в пределах той же самой мажорной версии (то есть приложение, собранное с Qt 5.5, будет работать с библиотеками от Qt 5.12, но приложение, собранное с Qt 4.x уже не будет работать с любыми библиотеками от Qt 5.x). Но… это при условии, что они собраны одним и тем же компилятором, потому что у разных C++ компиляторов может быть разная система декорирования имен, реализация виртуальных таблиц, и так далее, и тому подобное. Можно попытаться собрать Qt в статическом варианте и слинковать с вашим приложением статически, но… это в случае, если вы не используете модули из Qt, которые для работы используют плагины (например, работа с некоторыми форматами изображений или карты — OSM/HERE/Mapbox/...) — плагины существуют только в виде динамических библиотек, и их тогда придется поставлять в составе приложения тоже и обеспечивать, чтобы приложение могло их загрузить оттуда, где они будут лежать после его распаковки/установки. В общем, с этим все не так просто.
                                                      0
                                                      Если суметь сделать приложение на одном QML, его можно будет запускать при помощи qmlviewer на любой платформе без перекомпиляций.
                                            0
                                            Возможно. Я пока далек от JS.
                                              0

                                              Это если вы HTML5 + CSS знаете. Я не знаю, а сталкиваться иногда приходится, и впечатления, что это какая-то сверхлегкая технология, у меня нет. QML как-то попроще будет для свистелок-перделок.

                                          +3
                                          «раньше было лучше, на моем нетбуке с xp-шечкой все шустро запускалось, и бравзер и ворд и винумп и даже видосики 720p!!!


                                          Ну да, и я должен пойти на поводу у веб-макак и выкинуть свой верой и правдой служащий мне >10 лет ThinkPad T60 потому что какому-то придурку лень запускать профайлер и оптимизировать софт.

                                          Нуачо, ведь у абсолютно всех пользователей 64 гига оперативки. А тех, у кого 64 гигов нет — нужно спустить с парахода прогресса в биореактор, чтобы они не мешались.

                                          Правильно объясняю? :)
                                            –1
                                            Не правильно :) Всем просто плевать, что у вас ThinkPad T60 и специально под него оптимизировать ничего не будут.
                                            P.S. На мне злость за это сгонять не надо. Это не я пишу глючный софт на электроне чтобы он у вас не запускался. А то вон понакидали минусов, словно я автор всех приложений на электроне.
                                    +2
                                    Это возможный путь. Я иногда жалею, что начал с Python, а не с мира JavaScript.
                                      –1
                                      Все от задач зависит. Python — это мир бэкенда, решения научных задач, искусственного интеллекта и т.п. JavaScript — фронтэнд, визуальщина (можно и на сервере использовать, но это уже на любителя)…
                                        +1

                                        Python — мир клея между библиотеками. Алгоритмы ML не пишут на питоне, например (потому что медленно и нетипобезопасно). А когда на питоне пишут бекенд, то рано или поздно либо умирают под тяжестью динамической типизации, либо начинают делать из него пародию на хаскель, навешивая линтеры, тайпчекеры и проверяльщики чистоты.

                                          0
                                          Python — мир клея между библиотеками.

                                          Вы предпочитаете не пользоваться библиотеками? Или суперобъёмная std вас смущает? На вашем языке библиотеки не принято использовать?

                                          Алгоритмы ML не пишут на питоне

                                          Я вас удивлю, но пишут.

                                          бекенд, то рано или поздно либо умирают

                                          Это проблема архитектуры и IDE, а не языке. Посмотрите PyCharm.
                                            +2
                                            Вы предпочитаете не пользоваться библиотеками? Или суперобъёмная std вас смущает? На вашем языке библиотеки не принято использовать?

                                            Я предпочитаю языки, где я сам могу эффективно и безопасно писать библиотеки.


                                            Я вас удивлю, но пишут.

                                            Без опоры на numpy/чётамщасмодно? И как, не тормозит?


                                            Это проблема архитектуры и IDE, а не языке. Посмотрите PyCharm.

                                            Это проблема языка в первую очередь. Нельзя к языку адекватно прикрутить типизацию сбоку, если он был создан без расчёта типизации.

                                              0
                                              Вы любите самобытные языки? Небось, на ассемблере пишете без всяких там опор и библиотек?)
                                              Нельзя к языку адекватно прикрутить типизацию сбоку, если он был создан без расчёта типизации.

                                              Можно. Тем более, она в нём присутствует. Но даже если было бы нельзя, вам не хватило бы статического анализатора? Сдаётся мне, что какой-нибудь метод, который возвращает либо int, либо str, либо их кортежи, либо None, либо исключение — не есть проблема типизации.
                                                +2
                                                Вы любите самобытные языки?

                                                Вы не различаете «могу» и «должен»?


                                                Небось, на ассемблере пишете без всяких там опор и библиотек?)

                                                Да не, плюсы и хаскель в основном. В идеальном мире без легаси и с гуи-библиотеками заменил бы первое на раст.


                                                Можно. Тем более, она в нём присутствует.

                                                Вы про mypy? Так это ж и есть вот оно, прикрученное сбоку и разваливающееся (по личному опыту) при любом мало-мальски отходящем от C-style использовании типизации.


                                                Но даже если было бы нельзя, вам не хватило бы статического анализатора?

                                                Нет, конечно.


                                                Сдаётся мне, что какой-нибудь метод, который возвращает либо int, либо str, либо их кортежи, либо None, либо исключение — не есть проблема типизации.

                                                Проблема типизации в том, что вы про это не знаете и знать не можете.

                                                  –2
                                                  Похоже, проблема динамической типизации в том, что она вам не нравится. Иначе я не могу объяснить, почему для вас тип входных параметров является проблемой. В конце концов, вы сами можете проверить типы, использовать аннотации типов, использовать библиотеки типизации. С другой стороны, люди, которые в этом не нуждаются, могут использовать «чистый» язык. По-моему, это намного лучше, чем:
                                                  new public List<[CanBeNull] Dict<int,(byte[],Hasher)>> GetNamedHashesByID<in Hasher>(ref [NotNull] CryptoContainer seed, params int[] ids) where Hasher:ICryptoHashAlgoritm {...}
                                                    +2
                                                    Но так-то явно лучше:
                                                    GetNamedHashesByID(CryptoContainer seed, int[] ids)

                                                    чем так:
                                                    GetNamedHashesByID(seed, ids)

                                                    И гадать/всегда смотреть в доках, какого же типа аргументы.
                                                      –1
                                                      Кому явно? Кому лучше? Людям, которые в этом не нуждаются?
                                                      Проблема типизации в том, что вы про это не знаете и знать не можете.

                                                      GetNamedHashesByID(null, null);
                                                      GetNamedHashesByID(null, new int[0]);
                                                      

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

                                                      Ну и почему я должен половину работы сбрасывать языку, а вторую половину брать на себя? Тогда уж пусть язык сам все необходимые проверки делает и не выбрасывает исключения в рантайме или вообще не вмешивается. А если уж и вмешивается, то я сам хочу настроить, где и как.
                                                        +2
                                                        Теперь вам придётся гадать/всегда смотреть в доках, правильные ли значения аргументов были переданы.

                                                        Почему? Если они неправильные, то компилятор мне про это скажет, а IDE, c ним интегрированная, красненьким подсветит.


                                                        У вас там NotNull было на первом параметре? Так оно и ругнётся, что там null.


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

                                                        Не надо в рантайме.

                                                          –3
                                                          Почему?

                                                          Потому что они правильные для компилятора, но неправильные для функции. Если функция рассчитывает на непустой массив, а на вход дали «правильный», но пустой, то в рантайме вылезет исключение, не смотря на все статические проверки.
                                                          У вас там NotNull было на первом параметре?

                                                          chersanya по каким-то причинам предлагает выкинуть половину сигнатуры.
                                                          Не надо в рантайме.

                                                          Согласен, я так и написал.

                                                          chersanya,
                                                          Про пример с null не понял, какое именно утверждение вы им иллюстрируете.

                                                          Nullable тип является указателем на этот тип, поэтому может оказаться «просроченным».
                                                          чтобы избавиться от этой «половины» работы/багов/тестов.

                                                          Всё-равно ведь придётся писать вторую половину. От 10 лишних строчек я не умру, а вот читать и учить мануалы про внутреннее устройство языка, чтобы опустить проверку на null… Это намного больше усилий потребует, чем написать seed = seed || new DefaultSeed();
                                                            +2
                                                            Потому что они правильные для компилятора, но неправильные для функции. Если функция рассчитывает на непустой массив, а на вход дали «правильный», но пустой, то в рантайме вылезет исключение, не смотря на все статические проверки.

                                                            Значит, вы в типах выразили не все условия на входные параметры функции.


                                                            В C# (или какой это язык) выразить «непустость» массива сложно, но это не проблема типизации как таковой, а проблема конкретно C# как имеющего невыразительную систему типов.


                                                            chersanya по каким-то причинам предлагает выкинуть половину сигнатуры.

                                                            Только ведь всё равно получается лучше, чем в питоне. У вас хоть какие-то представления о типах есть. Ну и у компилятора тоже, да.


                                                            Nullable тип является указателем на этот тип, поэтому может оказаться «просроченным».

                                                            Не понял.


                                                            Опять же, я на C# не пишу и его не знаю, но если я в C++ пишу std::optional<int>, то где тут указатель? Или если я в хаскеле пишу Maybe Int, то где тут указатель?


                                                            Всё-равно ведь придётся писать вторую половину.

                                                            Только она может оказаться сильно меньше.


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


                                                            От 10 лишних строчек я не умру, а вот читать и учить мануалы про внутреннее устройство языка, чтобы опустить проверку на null…

                                                            Только язык вы учите один раз (и для адекватных языков эти концепции потом неплохо переносятся на другие языки), а 10 строк приходится писать постоянно.


                                                            Это намного больше усилий потребует, чем написать seed = seed || new DefaultSeed();

                                                            Только вот, увы, все проблемы от nullability это не покрывает.

                                                              –1
                                                              Только ведь всё равно получается лучше, чем в питоне.

                                                              1,228,588 репозиториев на гитхабе говорят об обратном (у С/С++ 549,210 репозиториев).
                                                              Nullable. Не понял. что значит «просроченным»

                                                              Это значит, что тип может иметь значение null. Такое значение нельзя привести к типу. Null — это отдельный тип. Поэтому, когда вы указываете nullable параметр в функции, вам надо это учесть. Компилятор не будет ругаться, даже если вы передали null вместо нормального значения. В итоге, в рантайме вылезет ошибка вида «Null reference exception».
                                                              Только она может оказаться сильно меньше.

                                                              А может и нет.
                                                              а 10 строк приходится писать постоянно.

                                                              Откройте для себя повторное использование кода.
                                                              Только вот, увы, все проблемы от nullability это не покрывает.

                                                              Какие?

                                                              В итоге, из обсуждения питоновских библиотек, алгоритмов и типов мы пришли к обсуждению null. Если вам нравится язык с 60% проверок, не надо говорить о бездарности языка с 40%, т.к. всегда найдётся 61% язык, который заявит о бездарности вашего.
                                                                0
                                                                1,228,588 репозиториев на гитхабе говорят об обратном (у С/С++ 549,210 репозиториев).

                                                                Если вы качество инструмента оцениваете по его популярности то лучше всех JS и PHP.


                                                                Только популярность с качеством не особо то коррелирует обычно.

                                                                  +1
                                                                  1,228,588 репозиториев на гитхабе говорят об обратном (у С/С++ 549,210 репозиториев).

                                                                  Кажется, мы обсуждаем количество информации, передаваемой при чтении кода, а не количество репозиториев.


                                                                  Это значит, что тип может иметь значение null. Такое значение нельзя привести к типу.

                                                                  Я тут совсем перестал понимать. У типа есть значение, которое нельзя привести к этому типу? Это как и в каком языке?


                                                                  Поэтому, когда вы указываете nullable параметр в функции, вам надо это учесть. Компилятор не будет ругаться, даже если вы передали null вместо нормального значения.

                                                                  Естественно. Ведь он же nullable!


                                                                  В итоге, в рантайме вылезет ошибка вида «Null reference exception».

                                                                  Так это проблемы реализации функции. Если она явно говорит, что может обработать null/Nothing/etc, но не делает этого, то функция врёт.


                                                                  Правда, разные языки различаются тем, тяжело ли в них врать или же это поведение по умолчанию.


                                                                  А может и нет.

                                                                  Ну, это вопрос личного опыта. Про свой опыт я там написал.


                                                                  Откройте для себя повторное использование кода.

                                                                  Как вы повторно используете тесты, проверки на входящие типы и прочие подобные вещи?


                                                                  Какие?

                                                                  Безболезненный рефакторинг, монадические вычисления (правда, тут уже Either и подобные полезнее, но не суть), краткий и выразительный код, при этом проверяемый компилятором.


                                                                  Если вам нравится язык с 60% проверок, не надо говорить о бездарности языка с 40%, т.к. всегда найдётся 61% язык, который заявит о бездарности вашего.

                                                                  Так я и говорю, что чем больше проверок я могу выразить, тем лучше. И тогда C++ бездарный по сравнению с хаскелем, а хаскель бездарный по сравнению с идрисом.

                                                                    0
                                                                    Кажется, мы обсуждаем количество информации, передаваемой при чтении кода, а не количество репозиториев.

                                                                    Я это не обсуждал. Возможно, вы меня перепутали с другим юзером.
                                                                    У типа есть значение, которое нельзя привести к этому типу?

                                                                    Например, создадим класс. Затем вызываем метод Hi.
                                                                    public class A {
                                                                     public void Hi()
                                                                     {
                                                                      Console.WriteLine("Hi!");
                                                                     }
                                                                    }
                                                                    A x = new A();
                                                                    x.hi(); //>>Hi

                                                                    Теперь присвоим переменной null. И повторим.
                                                                    
                                                                    x=null;
                                                                    x.hi(); //ошибка рантайма
                                                                    x = new null(); //ошибка компиляции

                                                                    Удивительно, но значение есть, а метода нет. Почему? Потому что null нельзя привести к A (у него нет смещения на метод Hi).
                                                                    Как вы повторно используете тесты, проверки на входящие типы и прочие подобные вещи?

                                                                    1. копипаст
                                                                    2. макросы
                                                                    3. библиотеки аннотаций, декораторов, атрибутов, других обёрток
                                                                    3. ide
                                                                    4. расширение компилятора, анализатора, языка
                                                                    5. чистые функции
                                                                    6. шаблонизаторы, генераторы и фреймворки
                                                                      +1
                                                                      Удивительно, но значение есть, а метода нет. Почему?

                                                                      Потому что вы взяли нулябельный язык.


                                                                      Существование языков с хреново спроектированными системами типов — не повод отказываться от систем типов. Вот, смотрите:


                                                                      foo :: Int -> Int
                                                                      foo x = x
                                                                      
                                                                      -- Nothing &mdash; это, считайте, такой null
                                                                      main = print $ foo Nothing

                                                                      Ой:


                                                                          • Couldn't match expected type ‘Int’ with actual type ‘Maybe a0’
                                                                          • In the first argument of ‘foo’, namely ‘Nothing’
                                                                            In the second argument of ‘($)’, namely ‘foo Nothing’
                                                                            In the expression: print $ foo Nothing

                                                                      1. копипаст
                                                                      2. макросы
                                                                      3. библиотеки аннотаций, декораторов, атрибутов, других обёрток
                                                                      4. ide
                                                                      5. расширение компилятора, анализатора, языка
                                                                      6. чистые функции
                                                                      7. шаблонизаторы, генераторы и фреймворки

                                                                      Чего только люди не делают, лишь бы не типы.

                                                                0
                                                                chersanya по каким-то причинам предлагает выкинуть половину сигнатуры.

                                                                Да, предлагаю, и при этом одновременно предлагаю брать язык, где null по-умолчанию не разрешён. Среди популярных языков выбор таковых имеется.

                                                                Потому что они правильные для компилятора, но неправильные для функции. Если функция рассчитывает на непустой массив, а на вход дали «правильный», но пустой, то в рантайме вылезет исключение, не смотря на все статические проверки.

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

                                                                Nullable тип является указателем на этот тип, поэтому может оказаться «просроченным».

                                                                Как уже правильно написали, «nullable-ность» типа и то, является ли он указателем, вещи не связанные. Вообще в прикладном программировании задумываться об указателях особо не приходится. И что значит «просроченным»?
                                                                  +2
                                                                  Разумеется нельзя все требуемые свойства входных параметров в общем случае вывести в тип аргумента. Например, если функция принимает на вход имя существующего файла.

                                                                  А это, кстати, довольно интересный пример.


                                                                  Я не думаю, что предикат «файл по указанному пути должен существовать» вообще имеет смысл, так как файл в любой момент может быть удалён (включая момент, когда вы половину аргументов для вызова функций на стек положили, а половину ещё нет).


                                                                  А вот предикат вроде «в списке не меньше N элементов» вполне может быть выражен. Даже для известных только в момент выполнения N.

                                                                    0
                                                                    А предикат вида «итеративный алгоритм, реализованный этой функцией, сходится для данного значения X» выразить можно, но смысла в этом особо нет — для проверки нужно выполнить, собственно, функцию.
                                                                      0

                                                                      Ну, да, речь о provably total вещах (например, «итеративный алгоритм, реализованный этой функцией, сходится для данного значения X за не более чем N шагов»). А вы больно близко ко всяким Тьюрингам подошли.

                                                                        0
                                                                        На практике дела это не меняет — всё равно проверка такого свойства для конкретного числа слишком времязатратна, чтобы каждый раз при вызове функции проводить.
                                                                          0
                                                                          На практике дела это не меняет — всё равно проверка такого свойства для конкретного числа слишком времязатратна, чтобы каждый раз при вызове функции проводить.

                                                                          А это уже зависит от того, нужно ли вам это в данном конкретном случае.


                                                                          Да и проверять длину в любом случае проще, чем выполнять произвольную функцию.

                                                                            0
                                                                            Да. Изначально мой посыл в том, что в статическом задании и проверке типов нужно где-то остановиться.
                                                            +2
                                                            Про пример с null не понял, какое именно утверждение вы им иллюстрируете. Лично я, например, предпочитаю языки, где по-умолчанию никакой тип null не разрешает, и нужно наоборот явно указывать где он может быть. Но этот момент ортогонален статическим/динамическим типам.

                                                            Ну и почему я должен половину работы сбрасывать языку, а вторую половину брать на себя?

                                                            По-моему ответ очевиден, разве нет? Чтобы избавиться от этой «половины» работы/багов/тестов.
                                                          +2
                                                          Похоже, проблема динамической типизации в том, что она вам не нравится.

                                                          Проблема динамической типизации (кстати, это немножко оксюморон1) в том, что она не даёт никаких статических гарантий. И я лучше потрачу немного времени, чтобы продумать типы, чем потом буду изобретать свой маленький тайпчекер для моего маленького частного случая в виде тестов.


                                                          Иначе я не могу объяснить, почему для вас тип входных параметров является проблемой.

                                                          Типы как раз проблемой не являются, проблемой является их отсутствие.


                                                          По-моему, это намного лучше, чем:

                                                          А было бы лучше, если бы функция возвращала всё это, но было написано просто GetNamedHashesById(s, is), вообще без какого бы то ни было указания, что такое s, что такое ids, и какими они должны быть?


                                                          ¹

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

                                                            0

                                                            Мне нравилось, что у lua динамическая типизация. Удобно для маленьких проектов и скриптов. Но я не изменять тип переменной и обращался с языком, как со статическим. Параметров в функциях не хватает.
                                                            GScript (язык движка Godot) позволяет указать явно тип, но пока не делает это правило обязательным.
                                                            После, близкого знакомства со swift, понял, что статическая типизация мне больше нравится, чем нет. Это просто удобно.

                                                              +1
                                                              Удобно для маленьких проектов и скриптов.

                                                              Ну фиг знает, мне от 10 строк с типами лучше.

                                                              –2
                                                              Динамическая типизация — это общее понятие, под которое можно подвести и nullable типы, и вариативность типов (
                                                              public type1, type2, type3 x = new type1();
                                                              ), и универсальный тип, и неявное автоприведение типов. А если вспомнить про супертипы, то открывается прекрасный дивный мир динамической типизации. Так ещё и системы вывода типов научились это дело проверять прямо в IDE.
                                                              А было бы лучше

                                                              Ну да. Это получается динамическая типизация второго порядка. А ещё IDE умеют автоматически разбивать динамически типизированные переменные на статически и размечать типы, когда достаточно написать пример использования.
                                                                +2
                                                                Динамическая типизация — это общее понятие

                                                                Так как его сформулировать-то? Любой if — признак динамической типизации, что ли?


                                                                под которое можно подвести и nullable типы

                                                                Компилятор вас всего лишь заставляет писать с учётом возможной нулябельности. Где ж тут динамическая типизация?


                                                                public type1, type2, type3 x = new type1();

                                                                Я не понял эту запись :(


                                                                и неявное автоприведение типов

                                                                Касты проверяются статически, и в большинстве языков непроверяемых даункастов нет.


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

                                                                Нет, апкасты всё равно происходят во время компиляции.


                                                                Ну и далеко не все любят языки, в системе типов которых есть отношение сабтайпинга.


                                                                А ещё IDE умеют автоматически разбивать динамически типизированные переменные на статически и размечать типы, когда достаточно написать пример использования.

                                                                А как это выглядит?


                                                                И чем это отличается от гарантированного вывода типов в стиле Хиндли-Милнера?


                                                                И какой тип выведется для функции


                                                                let v1 = f(True)
                                                                v1 += 5
                                                                
                                                                let v2 = f(False)
                                                                v2 += "str"

                                                                ?

                                                                  –1
                                                                  Так как его сформулировать-то?

                                                                  Так разве не вы написали? Привязка типов в райнтайме — динамическая, в компиляторе — статическая, причём 1 к 1.
                                                                  Компилятор вас всего лишь заставляет писать с учётом возможной нулябельности. Где ж тут динамическая типизация?

                                                                  В рантайме тип может поменяться на null.
                                                                  public type1, type2, type3 x = new type1();

                                                                  Переменная x может иметь либо тип1, либо тип2, либо тип3.
                                                                  Касты проверяются статически

                                                                  А выполняются в рантайме => динамическая.
                                                                  Нет, апкасты всё равно происходят во время компиляции.

                                                                  Только если типы можно вывести. Поэтому тоже динамическая.
                                                                  И чем это отличается от гарантированного вывода типов

                                                                  Большая гибкость, больше возможностей, меньше запретов, больше свободы.
                                                                    +2
                                                                    Так разве не вы написали? Привязка типов в райнтайме — динамическая

                                                                    Выполняемая языком.


                                                                    Если я на С стану писать, оперируя лишь структурами вида


                                                                    struct Any
                                                                    {
                                                                        void *something;
                                                                        int typeTag;
                                                                    };

                                                                    с ручными проверками typeTag перед каждой операцией, то динамически типизированным он от этого не станет.


                                                                    В рантайме тип может поменяться на null.

                                                                    Ну, во-первых, нет такого типа, как null, а, во-вторых, в рантайме-то ничего не меняется.


                                                                    Переменная x может иметь либо тип1, либо тип2, либо тип3.

                                                                    Мне неизвестны языки, в которых это так работает, поэтому здесь я ничего сказать не могу.


                                                                    А выполняются в рантайме => динамическая.

                                                                    Апкасты? В простейшем случае (который, на мой взгляд, покрывает значимую часть реальных случаев) нет, и апкасты не компилируются ни в одну исполняемую инструкцию.


                                                                    Только если типы можно вывести. Поэтому тоже динамическая.

                                                                    А можно пример апкаста, когда типы вывести нельзя?


                                                                    Большая гибкость, больше возможностей, меньше запретов, больше свободы.

                                                                    Если перед каждым знаком препинания подставить «сделать ошибку» :)


                                                                    Мне нравится ограничивать себя, потому что больше ограничений — меньше ошибок, меньше отладки, меньше геморроя.

                                                                      0
                                                                      А можно пример апкаста, когда типы вывести нельзя?

                                                                      class C:A,B {...}
                                                                      Множественное наследование, например. Куда будет приведён класс C? Непонятно, зависит от ситуации.
                                                                      Если я на С стану писать, оперируя лишь структурами вида с ручными проверками typeTag перед каждой операцией, то динамически типизированным он от этого не станет.

                                                                      Конечно, у вас типы уже привязаны заранее, а оперируете вы их значениями.
                                                                        0
                                                                        Множественное наследование, например. Куда будет приведён класс C? Непонятно, зависит от ситуации.

                                                                        Да, зависит от, условно, типа выражения слева от знака равенства. Так что это тоже статически известно.


                                                                        Конечно, у вас типы уже привязаны заранее, а оперируете вы их значениями.

                                                                        Так у меня нет никакого типа, кроме Any! Всё, что у меня есть — числовые метки, а их соответствие типам уже у меня в голове (и язык от меня не требует их проверять, я этот void* могу как угодно интерпретировать, и никто в рантайме меня не остановит.

                                                                          0
                                                                          Так что это тоже статически известно.

                                                                          Ну если всё статически известно, то в чём смысл программы? Посчитали один раз, а дальше распространяем результат. Не всё в этой жизни можно выразить статически.

                                                                          void * — это тип указателя
                                                                          int — это тип целого числа
                                                                          Не вижу тут динамической типизации.
                                                                            +1
                                                                            Ну если всё статически известно, то в чём смысл программы? Посчитали один раз, а дальше распространяем результат.

                                                                            В работе на данных, которые становятся известны после написания программы.


                                                                            Но да, если я беру наркоманский язык и использую его как прувер для доказательства чего-нибудь, то последующий код запускать необязательно.


                                                                            Не всё в этой жизни можно выразить статически.

                                                                            Какой-то странный аргумент в пользу динамичности конкретного выражения.


                                                                            Не вижу тут динамической типизации.

                                                                            Указателя на что?


                                                                            В этом вашем питоне

                                                            0

                                                            Т.е. вы видите, что rust удобнее для вас чем известный вам с++?

                                                              +1

                                                              Не то что удобнее, я на расте и не писал толком, просто я что-то стал бояться C++. Развлечение «а теперь найди в этом куске кода столько UB, сколько сможешь» не пошло на пользу моему душевному спокойствию.

                                                                –1
                                                                В растике вам точно так же придется бояться UB в unsafe блоках, так что ИМХО хрен редьки не слаще :) Я, поглядев на растик, пришел к выводу, что он, конечно, защищает… в каких-то очень тривиальных случаях, которые и так видны достаточно наметанным глазом. Но в нетривиальных случаях он так же беспомощен в плане защиты от дурака, как и C++. Растик, возможно, и хорош для джавистов/шарпистов, которые хотят написать что-то действительно быстрое и притом не облажаться, в пределах его safe подмножества, но не дай бог этим людям начать писать на нем unsafe код. Чтобы писать unsafe код на растике, нужно иметь ничуть не меньше опыта и понимания, чем чтобы писать на C/C++.
                                                                  0

                                                                  Ну почему любой тред, упоминающий C++ и растик, скатывается в обсуждение unsafe? Я не хотел, честно. Но придётся.


                                                                  Чтобы писать unsafe код на растике, нужно иметь ничуть не меньше опыта и понимания, чем чтобы писать на C/C++.

                                                                  Да, только на C++ у вас весь код ансейф, а на расте он явно выделен соответствующим образом.


                                                                  И не могу сказать про раст, но на том же хаскеле ансейф-код мне приходится писать примерно никогда. Даже FFI норм получается.

                                                                    0
                                                                    Да, только на C++ у вас весь код ансейф, а на расте он явно выделен соответствующим образом.

                                                                    Убер-аргумент, сдаюсь! :) Закрыли паллетами, значит, все хорошо. Да это я так, троллю, понятно, что все это уже по сто раз обсуждалось.

                                                                    И не могу сказать про раст, но на том же хаскеле ансейф-код мне приходится писать примерно никогда. Даже FFI норм получается.

                                                                    Вы просто выносите unsafe код в C/C++ либы, ну а к ним уже FFI :)))
                                                                      0
                                                                      Вы просто выносите unsafe код в C/C++ либы, ну а к ним уже FFI :)))

                                                                      На самом деле нет.


                                                                      FFI я дёргал либо к libclang (по очевидным причинам, компилятор плюсов я не буду писать ни на каком языке, увольте), либо к кое-каким алгоритмам, написанным на С. Просто оказывается, что gcc/clang оптимизируют код лучше, чем ghc или ghc+llvm, даже если там нет ничего невыразимого в сейф-сабсете хаскеля.


                                                                      Кстати, надо бы ту ерунду доделать и написать статью, с бенчмарками и вот этим всем.

                                                    0
                                                    Если точнее, python — это мир бэкенда+фронтенда, а javascript — только фронтенда.
                                                  0
                                                  Можно вместо встраивания сделать из вэб-интерфейса Progressive Web App. Либо вообще так и распространять в виде вэб-приложения. Пусть пользователь запускает index.html. Помню, делал так, вполне было юзабельно. Если надо в виде отдельного экзюка, то еще 10 лет назад писал простейший враппер на C++Builder, который использовал компонет WebBrowser и запускал то же самое вэб-приложение…
                                                    0
                                                    C index.html — понятно, с Progressive Web App — хочу ознакомится. Спасибо.
                                                  +4
                                                  А размер standalone приложения для MacOS будет всего 1 MB.

                                                  Грустно конечно, что для простейшего калькулятора миллион байт — это «всего».
                                                    +1
                                                    Мне кажется миллион байт для кросс-платформы это хорошо. Альтернативные варианты все сложнее и тяжелее.
                                                      0

                                                      Но скомпилированное приложение уже не является кроссплатформенным.

                                                        0
                                                        Как я понимаю, есть два варианта. Можно компилировать, а можно использовать в режиме интерпретации. Я не пробовал. Скорее всего будет медленнее. В официальной документации такого пути нет.
                                                    +6
                                                    А когда то сишники кричали что делфи жирные программы делает.
                                                    Посмотрел среди старых исходников написанный интереса ради калькулятор — 360 кб.
                                                    Куда мы идем хз.
                                                      0
                                                      С графическим интерфейсом? Без зависимостей?
                                                        +2
                                                        На чистом WinAPI можно написать GUI приложение с кучей свистелок, и занимать оно будет десятки килобайт от силы. Но трудоемкость написания возрастет в разы.
                                                          0
                                                          Это наверное похоже на то, что я сделал на Swift. На выходе бинарный файл 60кб, но ему нужны библиотеки swift и только одна libswiftCore.dylib занимает 6.8 Mb.
                                                            +2
                                                            Приложению на чистом WinAPI нужна только ОС. Обычно ОС все-таки не считают «зависимостью», а вот ОС без свифтовых библиотек вполне можно себе представить.
                                                              0

                                                              Как и ОС без WinAPI, если это к примеру Линукс или Мак…

                                                            0

                                                            Вы о какой трудоемкости вообще говорите? Кнопочек на форму накидал, процедур навешал и готово.

                                                            0
                                                            если не считать винду (а точнее winapi) зависимостью то да без зависимостей
                                                            зы можно было и под другие платформы компилить.
                                                              0

                                                              Но если под другую платфоому, то там должны быть библиотеки WinAPI, так? И тогда уже не 10 кб, а больше.

                                                                0
                                                                С какой это радости? Не, если кроссплатформенностью считать возможнось запуска одного и того же файла в разных системах, то кроме скриптов вообще варианта нет. Да и взять с собой в дорогу WinAPI все равно не выйдет по ряду причин.

                                                                Просто обычно под этим словом понимают возможность сборки нативных бинарников под разные системы из единого дерева исходников, и тут ничего с собой тащить не надо. Программы, собранные в FPC, могут на голом ядре Linux работать, и под винду тоже ничего не требуют, кроме самой системы.
                                                                  0

                                                                  Т.е. вы можете при сборке указать MacOS целевой платформой и получить бинарный файл готовый к использованию и без зависимостей?

                                                                    0
                                                                    Это работает только для консольных приложений. Если нужен кроссплатформенный GUI, то без зависимостей не обойтись.
                                                                      0
                                                                      Конкретно про MacOS не скажу, не имел дела, а вот для Windows и Linux все именно так. Понятно, что если программа сознательно грузит внешние библиотеки, то зависимости будут. Но если это приложение типа калькулятора (форма, кнопки, и сотня строк логики), то да, из одного исходника отлично собирается EXE и ELF, и ничего, кроме самой системы, им не нужно.

                                                                      P.S. Для Linux, в случае GUI-приложения, понятно, должен быть установлен XWindow и все, что ему нужно. Хотя, для извращенцев всегда есть возможность самостоятельной инициализации графики и ручной работы с фреймбуфером.
                                                                        0

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

                                                                          0
                                                                          В принципе, банальный gcc при правильном кодировании умеет и не такое. Он из одного исходника готов собрать как бинарник OSX, так и прошивку для AVR (если немного утрировать, конечно).

                                                                          Ядро Linux, например, не имеет никаких зависимостей (очевидно), и собирается в gcc. Туда же GRUB, uBoot, и еще куча софта, работающего на bare metal. Понятно, что калькуляторы без ОС запускать — глупость, но это просто как иллюстрация возможностей. Если инструмент умеет собирать под голое железо, то собрать под голое ядро ему тем более по силам.

                                                                          Но тут встает вопрос, насколько это нужно. Программировать так, чтобы бинарник собирался совсем без зависимостей, но использовал нечто большее, чем консольный ввод-вывод — чертовски затратное дело. Даже под одну платформу. А под несколько, так вообще ой.

                                                                          Delphi делает это при помощи довольно неоптимальной, местами глючноватой, совершенно ненативной библиотеки компонентов «FMX», которая, грубо говоря, линкуется статически прямо в бинарник. Велосипед чистой воды, конечно, но свою плюсы у него есть.
                                                                            0
                                                                            Понятно, что калькуляторы без ОС запускать — глупость, но это просто как иллюстрация возможностей.

                                                                            Ну, можно собрать из исходников FORTH под bare metal.

                                                                            Он сам по себе и язык программирования, и операционка, и калькулятор :)
                                                                              0

                                                                              Но это же будет чисто гиковский эксперимент.
                                                                              Мы же все равно дальше терминала не уйдем.

                                                                      0
                                                                      Взять в дорогу WinAPI можно в виде wine.
                                                                        0
                                                                        winelib — это не совсем то, что я имел в виду. Тем более, что за пределами x86[-64] там вообще все очень непросто.
                                                                  0
                                                                  С графическим интерфейсом и без зависимостей моя кубикокидалка (d2, d3, d4, d6, d8, d10, d20, d100 и произвольный + произвольное AdB+C), написанная на дельфи в 2004 году занимает ровно 320000 байт.

                                                                  И я считаю, что это очень много. По сравнению с JPEG Stripper'ом на 25600 байт. Или bred'ом на 183296 байт.
                                                                    0

                                                                    На сегодняшний день, какая есть альтернатива? Кроме electron. Не обязательно с визуальным интерфейсом.

                                                                      0
                                                                      Ну, сейчас выгоднее то же самое приложение написать для веба и запускать в браузере. Займет оно килобайт 5-6 и будет прекрасно работать без инета (собственно у меня есть такая кубикокидалка на 3800 байт, но реализует она не всё что умела дельфёвая версия).

                                                                      Электрон тут «нужен» разве что чтобы от браузера «отказаться», только это только видимость будет.

                                                                      А вот так, чтобы на выходе был бинарник… тут я вам не подскажу. Особенно если хочется бинарник кроссплатформенный.
                                                                        0
                                                                        Хорошо. Если нужно сделать приложение для веба, на что кроме Electron смотреть? React Native?
                                                                  0
                                                                  С динамической линковкой
                                                                  Со статической будет в разы тяжелее
                                                                    +2
                                                                    Это смотря с какой версией Delphi работать. Вот, например, не поленился, накидал по-быстрому простейший калькулятор на D3.
                                                                    Скриншот


                                                                    Без рантайм-пакетов получилось даже вдвое меньше, чем заявил demon416nds. И при этом реально никаких внешних зависимостей.

                                                                    А если вместо VCL использовать альтернативную библиотеку компонентов KOL, то получится еще раза в четыре меньше при таком же отсутствии зависимостей (модули KOL — обычные PAS/DCU-файлы и используются только при сборке EXE).

                                                                    P.S. С рантайм-пакетами в D3 получилось менее 12 килобайт, кстати.
                                                                      0
                                                                      когда я учился в ходу была 6 версия
                                                                      впрочем мог и 7 скомпилить давно было не помню
                                                                        0

                                                                        Хорошо, а в чем тогда подвох? Почему эта технология постепенно исчезает?
                                                                        Дизайн виджетов устарел?
                                                                        Можно ли на windows собрать программу для запуска в macOS, чтобы на macOS не устанавливать зависимости?


                                                                        Например, вы перешлете мне файл на 12 кб и я смогу запустить калькулятор?

                                                                          +2
                                                                          языковые войны однако
                                                                          delphi практически вытеснили с рынка
                                                                          настолько что их купила другая компания
                                                                          сейчас разработкой занимается не borland а embarkadero
                                                                          сломали интерфейс стремясь быть похожими на vs что оттолкнуло кучу разработчиков от новых версий.
                                                                          а потом и совместимость со старым кодом частично сломали ради улучшения кросплатформенности
                                                                          да, теперь кроме windows linux и macos можно компилировать и под ios с android
                                                                          но это требует переписывания кода и использования значительно более тормознутой системы gui.
                                                                          в общем на данный момент rad система практически мертва изза неправильного развития хоть разработчик и пытается увеличить популярность.
                                                                          lazarus живее (за счет бесплатности) но куда менее оптимизирован

                                                                          зы под линукс собрать точно можно было а вот под макось не пробовал
                                                                          там куча лицензионных заморочек чтоб эпплу в аду икалось
                                                                            –1
                                                                            Почему эта технология постепенно исчезает?

                                                                            Самый главный ответ: не модно.
                                                                            Как Фортран, Лисп и все остальные мегапопулярные языки прошлого.

                                                                            Дизайн виджетов устарел?

                                                                            Если используются системные виджеты, то как они могут устареть? Только вместе с ОС. А для несистемных там полное раздолье.

                                                                            Можно ли на windows собрать программу для запуска в macOS, чтобы на macOS не устанавливать зависимости?

                                                                            Да, причем, к сожалению, только так и можно. Сама среда Windows-only, как бы это странно не звучало.

                                                                            Например, вы перешлете мне файл на 12 кб и я смогу запустить калькулятор?

                                                                            Ну, 12 килобайт — это win32 с зависимостями. В моем примере win32 без зависимостей — это 190 КБ. Сколько он будет весить в исполнении OSX я не в курсе, но там совсем другой бекенд компилятора (LLVM, если правильно помню), и размер может отличаться кардинально.
                                                                              0

                                                                              Спасибо за ответ, теперь стало понятнее. Я пока работаю с MacOS.
                                                                              И пока из всех ответов я не нахожу решения проще чем предлагают разработчики языка Red.
                                                                              Устанавливаешь один файл, в нем все что нужно для работы и компиляции GUI приложения для разных платформ.


                                                                              Язык в версии 0.64, если доведут до конца, будет любопытная штука.


                                                                              Кстати, в нем сильно чувствуется наследие Scheme.

                                                                      0
                                                                      В плане кроссплатформенности, посмотрите на flow9.
                                                                        0

                                                                        Спасибо.
                                                                        Сегодня, пока общался на хабре открыл очень удобную библиотеку Python для визуализации данных streamlit
                                                                        Извините, что без ссылки.
                                                                        По принципу работы чем-то похоже на imgui и nuklear

                                                                          0

                                                                          Читаю обзор flow9 на сайте. Классная штука, завтра буду пробовать.
                                                                          Если окажется, проще чем Dart, то непонятно, почему малоизвестна.

                                                                          0
                                                                          Для своих программок с GUI использую wxpython, это python версия кроссплатформенной библиотеки WX Widgets. Под нее есть и билдеры всякие, для создания интерфейса перетаскиванием кнопочек, но я пишу кодом, как-то уже привык, несложно и удобно.
                                                                            0

                                                                            А кроссплатформа получается из коробки? Или нужно дополнительный упаковщик?

                                                                            +1

                                                                            Qt вполне хорош и проверен временем.

                                                                              +1
                                                                              Пример на tcl/tk
                                                                              За правильность логики самого калькулятора не ручаюсь, делалось на скорую руку. Но построение интерфейса видно. Количество строк можно сократить, но читать код будет труднее. Ну и сам внешний вид можно менять если взять ttk
                                                                              wm title . "Tcl/TK calc"
                                                                              pack [frame .frm] -expand true -fill both
                                                                              grid columnconfigure .frm 0 -weight 1
                                                                              grid rowconfigure .frm 0 -weight 1
                                                                              
                                                                              entry .frm.ent
                                                                              grid .frm.ent -row 0 -columnspan 5  -sticky nswe -padx 5 -pady 5
                                                                              
                                                                              proc Calculate {ent txt} {
                                                                                  if [regexp -nocase -all -- {([0-9]+)(\+|\*|\/|-)([0-9]+)} $txt match v1 v2 v3] {
                                                                                      $ent delete 0 end
                                                                                      $ent insert end [expr double($v1) $v2 double($v3)]
                                                                                  }
                                                                              }
                                                                              
                                                                              set col 0
                                                                              set row 1
                                                                              foreach item {1 2 3 4 5 6 7 8 9 0 + - * /} {
                                                                                  button .frm.btn_$item -text "$item" -command [list .frm.ent insert end $item]
                                                                                  grid .frm.btn_$item -row $row -column $col -sticky nswe -padx 5 -pady 5
                                                                                  incr col
                                                                                  if {[expr fmod($col, 5)] eq "0.0"} {
                                                                                      incr row
                                                                                      set col 0
                                                                                  }
                                                                              }
                                                                              button .frm.btn_calc -text "=" -command {
                                                                                  Calculate .frm.ent [.frm.ent get]
                                                                              }
                                                                              grid .frm.btn_calc -row 3 -column 4 -sticky nsw -padx 5 -pady 5
                                                                              


                                                                              image
                                                                                0

                                                                                Хорошо, а что нужно, чтобы получить бинарный файл для MacOS?

                                                                                  0

                                                                                  Или просто достаточно установленных библиотек tcl/tk?

                                                                                    0
                                                                                    Достаточно. Данный код будет работать везде где есть tcl/tk
                                                                                    Если надо украшательства то треба использовать ttk, он с недавних пор входит в базовую поставку tk
                                                                                    0
                                                                                    Под мак не знаю, под линукс и виндовс starpack есть, либо freewrap, скорее всего для мака тоже есть.
                                                                                  0
                                                                                  import calc
                                                                                  calc()

                                                                                  Две строчки. Я победил.
                                                                                  0
                                                                                  Раз уж пошли мериться размерами калькуляторов
                                                                                  1262 байт. Сохранить в файл с именем calc.hta (работает только под win)
                                                                                  calc.hta
                                                                                  <html>
                                                                                  
                                                                                  <head>
                                                                                      <meta charset="utf-8">
                                                                                      <meta http-equiv="X-UA-Compatible" content="ie=9">
                                                                                      <title>calc</title>
                                                                                      <HTA:APPLICATION border="dialog" maximizeButton="no" icon="calc.exe" applicationName="calc" innerBorder="no" navigable="no" scroll="no" />
                                                                                      <style>
                                                                                          * {
                                                                                              font-family: monospace;
                                                                                          }
                                                                                      </style>
                                                                                  </head>
                                                                                  
                                                                                  <body>
                                                                                      <input type="text" id="c" /><br>
                                                                                      <script>
                                                                                          window.resizeTo(200,200)
                                                                                          var c = document.getElementById('c');
                                                                                          [
                                                                                              7, 8, 9, '-', 0,
                                                                                              4, 5, 6, '/', 0,
                                                                                              1, 2, 3, '*', 0,
                                                                                              '0', '.', '+', '='
                                                                                          ].map(function (e) {
                                                                                              if (!e) {
                                                                                                  document.body.appendChild(document.createElement('br'));
                                                                                              } else {
                                                                                                  var i = document.createElement('input');
                                                                                                  i.value = e;
                                                                                                  i.type = "button";
                                                                                                  document.body.appendChild(i);
                                                                                                  i.addEventListener('click', function () {
                                                                                                      if (e == '=') {
                                                                                                          try { c.value = eval(c.value); } catch (e) { }
                                                                                                      } else {
                                                                                                          c.value += e;
                                                                                                      }
                                                                                                  });
                                                                                              }
                                                                                          });
                                                                                      </script>
                                                                                  </body>
                                                                                  
                                                                                  </html>
                                                                                  

                                                                                    0

                                                                                    Моих знаний JS, для такой штуки достаточно. Спасибо. Этой штуке не нужен браузер?

                                                                                      0
                                                                                      hta запускается в своём окне на движке ие (может эдж в более поздних виндах, у меня его нет).
                                                                                        0
                                                                                        ru.wikipedia.org/wiki/HTML_Application
                                                                                        Кроме стандартных браузерных js функций доступен системный api
                                                                                        Пример чтения локального файла
                                                                                        Заголовок спойлера
                                                                                        <html>
                                                                                        
                                                                                        <head>
                                                                                            <meta charset="utf-8">
                                                                                            <meta http-equiv="X-UA-Compatible" content="IE=8">
                                                                                            <meta name="viewport" content="width=device-width, initial-scale=1">
                                                                                            <title>TEST</title>
                                                                                        </head>
                                                                                        
                                                                                        
                                                                                        <body>
                                                                                        
                                                                                            <div id="content"></div>
                                                                                        
                                                                                            <script language="VBScript">
                                                                                            Function loadLocalFile(fileName)
                                                                                            set oFSO = CreateObject("Scripting.FileSystemObject")
                                                                                            set oFile = oFSO.OpenTextFile(fileName, 1)
                                                                                            text = oFile.ReadAll
                                                                                            oFile.Close
                                                                                            loadLocalFile = text
                                                                                            End Function
                                                                                            </script>
                                                                                        
                                                                                            <script type="text/javascript">
                                                                                            
                                                                                            document.getElementById('content').innerText = loadLocalFile('lorem.txt');
                                                                                        
                                                                                            </script>
                                                                                        
                                                                                        </body>
                                                                                        
                                                                                        </html>
                                                                                        


                                                                                      0
                                                                                      У меня создается ощущение, что в заголовке статьи вы пропустили слово. Идеальный в чем? В размере бинарника? В количестве строк для реализации калькулятора? В кроссплатформенности?
                                                                                        0
                                                                                        Я понимаю, что слово «идеальный» требует пояснений.

                                                                                        1. Простая установка на любую платформу (скачиваем установщик или собираем c помощью make или cmake имея только gcc или clang)

                                                                                        2. Возможность собрать приложение для работы на разных платформах. Компиляция или другие способы. Без проблем и дополнительных инструментов. Желательно одна или две команды в терминале.

                                                                                        3. Приложение на выходе меньше 50 мб
                                                                                          0

                                                                                          А чем всё-таки старый добрый C++ с Qt не угодил? Вроде все взрослые дяди его используют. Или как в той шутке: «чего только не придумают, чтобы не учить C++»?

                                                                                            0

                                                                                            Если у человека основная область деятельности далека от разработки ПО, то C++ ему все-таки в руки лучше не давать. Пусть уж прототипирует на том же Питоне то, что ему надо, а вот если это нужно будет потом запустить в продакшн под нагрузочкой, то тут уже можно и на C++ это перевести с помощью специально обученных людей. Тем более для Питона существуют официальные Qt-биндинги:


                                                                                            https://www.qt.io/qt-for-python
                                                                                            https://doc.qt.io/qtforpython/tutorials/qmlapp/qmlapplication.html

                                                                                              0

                                                                                              С другой стороны — зачем тогда прототипировать сразу на несколько платформ?

                                                                                                0
                                                                                                Ну так нагрузка может для какой-то конкретной задачи и вовсе не предполагаться — скажем, уровня условного «калькулятора»: какие-то формочки там, в которые вбиваются определенные данные, затем над ними производятся какие-то несложные расчеты. Зачем там C++ в прикладном коде? Он там не нужен. Тем не менее кроссплатформенность даже в таких задачах вполне может быть нужна.
                                                                                                  0

                                                                                                  Итого, стоит изучить что предлагает qt и насколько удобно сделать на нем приложение.
                                                                                                  Спасибо.

                                                                                        0
                                                                                        На python есть PySimpleGUI — кроссплатформенная библиотека, поддерживает tkinter, Qt, WxPython, Remi (в браузере).
                                                                                        Более 100 демо-программ
                                                                                          0
                                                                                          45MB
                                                                                          10 MB
                                                                                          1 MB.

                                                                                          Стандартный виндоус калькулятор 115 кБ.
                                                                                            0
                                                                                            Мне такой размер нравится, но какой инструмент можете посоветовать для такого типа приложений?

                                                                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                          Самое читаемое