Groovy vs Java для JavaFX

    image

    JavaFX хороша!


    Сначала пару слов об JavaFX. Чем нам понравилось с ней работать.

    Современный API. Даже без «билдеров», все выглядит очень современно.

    Тотальный Data Driven Development. Обожаем это. Логика основанная на связке данных очищает код от хлама, гетеры/сеттеры — «долой!». Работа с событиями изменения данных, дву-направленный «биндинг».

    FXML. Отличная вещь для прототипирования. Понятна дизайнеру, имеется хороший визуальный инструмент от Oracle — «JavaFX Scene Builder». Отмечу, что потом нам все же захотелось переписать FXML в виде обычного кода. Просто поддерживать FXML сложнее чем код — править приходится всегда два файла, код и FXML. Плюс когда используется код легче пользоваться наследованием.

    Nodes. Структура компонентов. Можно бегать по дереву. Можно искать по lookup(). Как в DOM. Прям jQuery пиши.

    CSS. Это действительно Вещь. «Скинуем» компоненты через один общий css-файл. ID-шники, CSS-классы, селекторы и псевдоселекторы.

    Text Engine. Очень хороший движок для сложных текстов.

    WebView. Реализуем навороченные компоненты на движке Webkit. Об этом читать предыдущую статью.

    Что не очень хорошо


    Это хорошее. Что плохо? JavaFX скрипт в свое время не просто так придумали. Создавать поля для доступа к Bindable данным через гетеры и сеттеры — это какой-то шаг назад и вчерашний день. Java тут не очень хороша. В Java 8 есть лямбда-выражения, но появление их тоже ответ на вопрос, что с Java что-то нужно делать и повод задуматься о более кардинальном решении.

    Groovy!


    Мы решили все эти проблемы для себя выбрав Groovy. Лаконичен, в хорошем смысле стар (вызрел) и хорошо поддерживается в IDEA. Groovy позволил нам сократить объем кода раз в десять точно. Работает, выглядит и читается почти как Java, но как же он хорош с точки зрения компактности!

    Есть еще куча хороших и красивых языков для JVM, но так сложилось что Groovy нас устраивает. Да и любим мы скобочки, аннотации и не хотим мы что-то тут в себе ломать. Плюс у меня лично был семи-летний опыт использования Groovy, а когда есть эксперт в команде, то лучше воспользоваться, а не брать что то совсем неведомое.

    Кстати Groovy по популярности языков (по данным TIOBE) занимает 18 место.

    Наши практики


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

    Конфигурирование компонентов


    Просто создаем экземпляр компонента через код и его конфигурируем.
    На Java нам приходилось пошагово, строчка за строчкой, присваивать значения.

    Button button = new Button();
    button.setFocusTraversable(false);
    button.setLayoutX(23);
    button.setPrefHeight(30);
    button.setPrefWidth(30);
    button.setText("ADD");
    

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

    Button button = new Button(focusTraversable: false, layoutY: 23, prefHeight: 30, prefWidth: 30, text: "Add")  
    

    Груви, напомню, кто не знает, позволяет обращаться к методам доступа (геттерам, сеттерам) без приставки set/get. То есть если в классе есть метод setText — то его вызов производится через простое присвоение значения — text = «Add». Плюс при компиляции Groovy классов, публичным полям добавляются геттеры и сеттеры автоматически. Поэтому из груви не прянято вызывать метод set/get если для этого нет реальной необходимости.

    А в параметры конструктора можно передавать пары — имя: значение (на самом деле это обычных HashMap и синтаксис тут используется Groovy Maps — [key1:value1, key2:value]).

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

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

    Можно!

    menus.addAll(
            new Menu(text: "File", newItems: [
                    new MenuItem(
                            text: "New Window",
                            onAction: { t ->
                                ApplicationUtil.startAnotherColtInstance()
                            } as EventHandler<ActionEvent>,
                            accelerator: new KeyCodeCombination(KeyCode.N, KeyCombination.SHORTCUT_DOWN)
                    ),
                    new Menu(text: "New Project", newItems: [
                            newAs = new MenuItem(
                                    text: "New AS Project",
                                    id: "new-as",
                                    onAction: { t ->
                                        ProjectDialogs.newAsProjectDialog(scene, false)
                                    } as EventHandler<ActionEvent>
                            ),
                            newJs = new MenuItem(
                                    text: "New JS Project",
                                    id: "new-js",
                                    onAction: { t ->
                                        ProjectDialogs.newJsProjectDialog(scene, false)
                                    } as EventHandler<ActionEvent>
                            )
                    ]),
                    new SeparatorMenuItem(),
                    new MenuItem(
                            text: "Open Project",
                            onAction: { t ->
                                ProjectDialogs.openProjectDialog(scene, false)
                            } as EventHandler<ActionEvent>,
                            accelerator: new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN)
                    ),
                    recentProjectsSubMenu = new Menu(text: "Open Recent", newItems: [
                            clearRecentProjects = new MenuItem(
                                    text: "Clear List",
                                    onAction: { t ->
                                        RecentProjects.clear()
                                    } as EventHandler<ActionEvent>
                            ),
                    ]),
                    new SeparatorMenuItem(),
                    save = new MenuItem(
                            text: "Save Project",
                            id: "save",
                            onAction: { t ->
                                ProjectDialogs.saveProjectDialog()
                            } as EventHandler<ActionEvent>,
                            accelerator: new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN),
                            disable: true
                    ),
                    saveAs = new MenuItem(
                            text: "Save As...",
                            onAction: { t ->
                                ProjectDialogs.saveAsProjectDialog(scene)
                            } as EventHandler<ActionEvent>,
                            accelerator: new KeyCodeCombination(KeyCode.S,
                                    KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN),
                    ),
                    new MenuItem(
                            text: "Close Project",
                            onAction: { t ->
                                ProjectDialogs.closeProjectDialog()
                            } as EventHandler<ActionEvent>,
                            accelerator: new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN),
                    ),
                    new SeparatorMenuItem(),
                    new MenuItem(
                            text: "Exit",
                            onAction: { t ->
                                ApplicationUtil.exitColt()
                            } as EventHandler<ActionEvent>
                    ),
            ]),
            new Menu(text: "Help", newItems: [
                    new MenuItem(
                            text: "Open Demo Projects Directory",
                            onAction: { t ->
                                ProjectDialogs.openDemoProjectDialog(scene)
                            } as EventHandler<ActionEvent>
                    ),
                    new MenuItem(
                            text: "Open Welcome Screen",
                            onAction: { t ->
                                ProjectDialogs.openWelcomeScreen(scene)
                            } as EventHandler<ActionEvent>
                    ),
            ])
    )
    

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

    Динамические свойства и методы


    Внимательный читатель спросит, а что за поле «newItems» у Menu? Да, такого метода у класса Menu нет. А добавили мы такой метод, потому что поле items" мы можем только читать, но не можем присваивать. У него нет метода «setItems()», а есть только «getItems()» и присваивать новое значение нельзя. Read-only. Чтобы конфигурировать Menu в виде структуры, мы добавили динамическое поле.

    Добавить такое поле очень просто, но наша Java сущность долго сопротивлялась такой крамоле как динамические методы. Мы много напридумывали велосипедов, пока не смирились с фактом необходимости воспользоваться динамикой. А все оказалось просто и нестрашно.

    Добавление динамического полей мы вынесли в отдельный класс GroovyDynamicMethods. Вот его код:

    class GroovyDynamicMethods {
    
        private static inited = false
    
        static void init() {
            if(inited)return
            inited = true
    
            addSetter(javafx.scene.Node, "newStyleClass", { String it ->
                styleClass.add(it)
            })
            addSetter(Parent, "newChildren", {List<MenuItem> it ->
                children.addAll(it)
            })
            addSetter(Menu, "newItems", {List<MenuItem> it ->
                items.addAll(it)
            })
        }
    
        private static void addSetter(Class clazz, String methodName, Closure methodBody) {
            addMethod(clazz, "set" + methodName.capitalize(), methodBody)
        }
    
        private static void addMethod(Class clazz, String methodName, Closure methodBody) {
            ExpandoMetaClass exp = new ExpandoMetaClass(clazz, false)
            exp."$methodName" = methodBody
            exp.initialize()
            clazz.metaClass = exp
        }
    }
    

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

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

    image

    Теперь IDEA знает о существовании таких полей, как будто они есть в API JavaFX.

    Работа с Bindable свойствами


    Связывание данных, замечательна штука. У нас в команде используется такая мантра — «Если что-то можно сделать через байндидинг, делай через байндинг». "… чтобы потом не переделывать".

    Бандинг позволяет связать модель данных, и компоненты. UI-компоненты сами имеют байндинг свойства, которые можно связывать с данными модели или строить на изменении этих свойств логику — подписываться на события изменения данных.

    Простой пример CheckBox:

    CheckBox checkBox = new CheckBox();
    checkBox.selectedProperty().bindBidirectional(selectedProperty);
    

    А тут мы реагируем на событие нажатия на чекбокс:

    CheckBox checkBox = new CheckBox();
    checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() {
        @Override
        public void changed(ObservableValue<? extends Boolean> value, Boolean before, Boolean after) {
            System.out.println("value = " + value);
        }
    });
    

    Использовать удобно. Не очень удобно такие свойства описывать.

    Java предлагает такой вот сценарий (код создан IDEA автоматически).

    private StringProperty name = new SimpleStringProperty(); // создали свойство
    
    //даем ссылку на свойство наружу (но не даем его изменять внешне)
    public StringProperty nameProperty() {
        return name;
    }
    
    // можно взять значение
    public String getName() {
        return name.get();
    }
    
    // даем возможность присвоить свойству новое значение
    public void setName(String name) {
        this.name.set(name);
    }
    

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

    Решение! Берем AST трансформацию, которая для нас этот код генерирует. При компиляции.

    Наше свойство (которое мы описали в Java 10 строками) превращается в Groovy в одну строку и выглядит так:

    @FXBindable String name;
    

    @FXBindable вы можете взять в GroovyFX, или можете взять нашу.
    Мы сделали форк такой аннотации и вы можете ее взять у нас на гитхабе.

    Плюс в этом же проекте вы обнаружите файл с расширением .gdsl, который научит IDEA пользоваться этой аннотацией — автокомлит и т.д.

    Такая трасформация, так же создает методы setName, getName, getNameProperty. Плюс к этому еще добавляется метод name() который позволяет получить доступ к полю написав еще меньше букв. Вкусовщина, но мы чаще всего пользуемся именно этим методом.

    this.nameInput.textProperty().bindBidirectional(this.name()) // this.name() - это наше строковое поле name
    

    Долой анонимные классы


    В примере с Menu мы подписываемся на события через анонимные классы. На примере структуры меню видно, что обработчиком событий выступает «кложура».

    onAction: { t ->
        ProjectDialogs.newAsProjectDialog(scene, false)
    } as EventHandler<ActionEvent>
    

    Вся магия в «as EventHandler» — тело кложуры перемещается в тело метода handle, класса EventHandler. Использование такой краткой записи для обработки событий делает код чище. Кстати умная IDEA предлагает квикфис «Change to dynamic instantiation». Так же можно использовать другую записать — через Map ([handler1: {}, handler2: {}]), если класс обработчик требует перегрузить несколько методов.

    Работа с XML


    В нашем проекте нам нужно было сериализовать модель данных в XML и брать ее с диска. Сначала хотели по привычке воспользоваться XStream, но нам нужна была более управляемая структура — Bindable свойства JavaFX они большие, а конвертеры писать лень. Посмотрели JAXB, тоже плохо. Тоже и с Groovy XML-сериализацией.

    Подошел встроенный в Groovy SDK XmlSlurper.

    Каждый Bean модели реализует два метода — buildXml и buildModel — сериализация и десериализация

    Closure buildXml(Project project) {
       return {
    		  'launcher'(launcherType)
          'browser-path'(browserPath)
          'nodejs-path'(nodejsPath)
          'console-value'(console)
        }
    }
    
    @Override
    void buildModel(Object node) {
        launcherType = node.'launcher'
        browserPath = node.'browser-path'
        nodejsPath = node.'nodejs-path'
        console = node.'console-value'
    }
    

    Метод buildXml возвращает структуру в виде кложуры. Магия тут в вызове и присвоении несуществующих методов и свойств. Если вызывается несуществующий метод — то создается свойство в виде дочерней ноды, если присваивается значение несуществующему полю — создается аттибут XML, если вызывается несуществующий метод и ему как пораметр передается кложура — то создается вложенная структура XML нод.

    Метод buildModel принимает аргумент node, и через динамические запросы ноду разбирает.

    Работа с файлами


    Наша программа много работает с файловой системой. Используя Groovy мы смогли сильно сократить код IO. Нам не нужно было экономить каждую наносекунду, у нас не нагруженный web-сервер, и то что Groovy делал за нас кучу работы нас устраивало.

    Groovy SDK предлагает множество полезных расширений для классов Java в том числе File. Например, возможность писать/читать содержимое файла просто через поле «text», или же работа со строками файла с помощью «splitEachLine».

    Кроме этого нам понравился AntBuilder, который можно использовать также для поиска и фильтрации файлов.

    Следующий пример копирует файлы:

    def ant = new AntBuilder()
    ant.sequential {
        myDir = "test/to/"
        mkdir(dir:myDir)
        copy(todir:myDir) {
            fileset(dir:"text/from/") {
                include(name:"**/*.*")
            }
        }
    }
    

    Вы можете искать файлы по шаблону с помощью fileScaner:

    def ant = new AntBuilder()
    def scanner = ant.fileScanner {
        fileset(dir: file) {
            include(name: "**/*.jpg")
        }
    }
    scanner.each{ printlt(it) }
    

    И конечно же AntBuilder — это полноценный ANT, со всеми его расширениями и возможностями. Здесь еще изучать и изучать. Gradle тоже использует AntBuilder, и то что там можно «наворотить» нас впечатляет.

    Использование GPath для работы с Nodes


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

    Например, чтобы убрать скролы на Java:

    webView.getChildrenUnmodifiable().addListener(new ListChangeListener<Node>() {
        @Override
        void onChanged(ListChangeListener.Change<? extends Node> change) {
            Set<jNode> scrolls = webView.lookupAll(".scroll-bar");
            for (Node  scroll : scrolls) {
                scroll.setVisible(false);
            }
        }
    });
    

    Тоже самое на Groovy:

    webView.childrenUnmodifiable.addListener({ change ->
        webView.lookupAll(".scroll-bar")*.visible = false
    } as ListChangeListener)
    

    Боремся с NPE


    Оператор «?.» — по нашему мнению, только он один, может заставить задуматься о переходе с Java на Groovy.

    model?.projectSettings?.projectPaths?.livePaths?.each{ println(it) } 
    

    Переводим это в Java и получаем как минимум двадцать строк кода.

    Заключение


    Вот и пожалуй все, что мы смогли вспомнить. Конечно же в нашем проекте мы использовали и другие «вкусности» Groovy, но если все перечислить, то мы выйдем за рамки статьи, да и учебников по Groovy можно найти много.

    Но хочется поговорить и о том, что нам не подходит из Groovy. Первое — мы избегали лишней динамики. В нашей команде мы договорились о том, что обязательно нужно указывать тип при создании любой переменной или поля (кроме параметров кложур — тут теряется половина удовольствия от них). Так-же, мы не использовали mixins и перегруженные операторы. Жонглирование кодом мы считаем вредной практикой — нам важен не только компактный, но и контролируемый, поддерживаемый код. Вот пожалуй и все. Groovy очень похож на Java и мы использовали его именно в этом контексте — мы знаем что за нас при компиляции производятся AST трансформации и мы при написании кода предполагаем, что к какой-то конструкции за нас что-то еще добавляется автоматом. Такая вот Java с автогенерацией. И больше ничего нам не нужно.

    Сайт проекта codeorchestra.com
    CodeOrchestra
    Company
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 37

      0
      С подключением:)
        0
        Как называется тема подсветки кода на картинке?
          +1
          IDEA Dark Theme — Darcula
          +3
          Кажется сам создатель грува говорил как то, что если бы в то время когда он наколякал свой псевдо-язык существовала бы scala то он бы этого не делал. Груви выглядит аппетитно особенно для людей кто вынужден годами терпеть отсталость java, но стоит заглянуть под капот и посмотреть как выпилен груви то становится тошно, особенно если знать тот факт что сам этот псевдо-язык задумывался для «скриптования» под jvm. Популярность языка в том или ином индексе ни очем не говорит, 10 лет назад в топ 10 входил кобол. Не обольщаейтесь прелестями груви они обманчивы, выбирайте scala за ней будущее.
            0
            Довольно часто упоминаемая цитата при обсуждении Groovy vs Scala:

            I can honestly say if someone had shown me the Programming in Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy.

            Scala as the long term replacement for java/javac? by James Strachan.

            Вольный перевод:

            Честно говоря, если бы мне показали книгу Programming in Scala в 2003 году, то я бы не создал Groovy.
              +4
              Да, фразу эту можно часто услышать. Только вот создатель Груви (Джеймс Стрэчен) уже давно не ее автор. Поглядите на фичи, которые были добавлены после его ухода (2007) от разработки. Это совсем другой язык.
              То что Стрэчену нравится Скала, не говорит что Groovy плох. Лично сам ничего не имею против Скалы, но счастлив что у меня есть выбор.

              И еще посмотрите на Gradle — как он помогает жить и как он набирает популярность. Это Groovy.
                +1
                Насчет Gradle, у scala есть sbt. И за груви давно тянется душок связанный с просто феноменальным отставанием в быстродействии по некоторым алгоритмическим задачам, такие своего рода кратеры на ровном месте. А так же шарм и магия груви до сих пор не позволяют запускать его под Android, хотя попытки ведутся и скажем так с большим боем, но что толку бить об стену горохом.
                  +1
                  Да я и не спорю что Scala хороша. Просто каждый выбирает что ему подходит. Мы выбрали Groovy и довольны.
                  С удовольствием почитаю статью про Scala + JavaFX.
                  Думаю мысль там будет та же — «зачему мучаться и есть кактус, когда можно сделать все быстро и весело».
                    0
                    Еще отмечу, что для нас главный минус Scala был — плохая поддержка в IDEA и шикарная (!) поддержка Groovy.
                    Выучить язык можно. И как бы все клёво. Но писать нужно на инструменте.
                    Может ошибаюсь на счет поддержки в IDEA? Может что стало лучше?
                    На Скалу поглядываю и то что для мобильной разработки можно использовать это действительно огромный плюс.
                    Порою тут побольше. Спасибо.
                      0
                      Поддержка в IDEA не идеальна, но хороша, на мой взгляд. Хорошо работает даже с implicit-ами, достаточно простыми.

                      Есть мелкие нарекания. Вроде того, что все еще самый удобный способ создания проекта — sbt gen-idea.

                      Не справляется с path-dependent types, сложными выражениями с использованием shapeless и scalaz, но если вы используете такое, то поддержка IDE для вас не главное.
                      +1
                      1) sbt до Gradle очень далеко.
                      2) Scala требует огромных финансовых вливаний в профессиональную подготовку программистов. Она сложна и это плохо для маленьких проектов.
                        0
                        Не соглашусь с вами по первому пункту, так как это очевидно субъективное мнение человека не очень хорошо знакомого с sbt, я кстати сказать не пытался донести до вас идею что gradle далеко до sbt. По второму пункту не соглашусь с вами, но соглашусь с создателем lift который в одной из своих статей пришел к выводу что есть есть две категории программистов, те которые адаптируют scala и те которые не способны этого сделать в виду определенных ограничений. Ведь scala несет в себе двойную парадигму, где нужно не просто менять язык но и подход а груви ничего такого не несет так как был задуман как скриптовый псевдо-язык.
                          +1
                          К сожалению, создатель lift использует не совсем честные аргументы, мол скала только для опытных/умных/..., разумеется, опытный программист сможет писать на любом языке. Сложность скалы должна где-то окупаться, лучше начать с этих примеров.
                            0
                            К сожалению опыт к успешному освоению скалы имеет второстепенное отношение. Ведь как я уже говорил выше, скала это не просто другой язык но это и совершенно другой подход и стиль. Тут все зависит от мотивации обучаемого. Точно такая же ситуация с js, есть упрямые люди которые рассматривают его как обычный ООП язык и пишут на нем как курица лапой а ведь js это прежде всего ПОП (не путать с бородатым дядькой с кадилом). Про сложность языка я бы промолчал, так как такой величины для инженера не существует. А про окупаемость могу лишь сказать что закон Мура не работает уже пару лет, делайте выводы сами.
                              +1
                              Разделение сложности языка и сложности стиля/подхода тоже не совсем честное, ведь раз мы пишем на скале, значит нужно использовать соответствующий поход. И, как вы сами написали, для инженера это должно быть проблемой. Остается вопрос зачем? Инженер может писать код точно так же на яве, имея сравнимое быстродействие. Если говорить о многопоточных приложениях, то какие конкретно преимущества дает скала?
                              Яваскрипт бы оставил для других дискуссий, но подходы имеют место быть разные, классы вполне себе появятся в es6 и я не думаю, что это случайность.
                                0
                                Когда вы пишите на скале никто не обязывает вас быть FP-only хотя это рекомендовано. Не знаю знакомы ли вы с презентацией презентацией Bret Victor about the future of programming. Кстати я склонен полагать что именно из за всеобщей любви к ООП мы до сих пор топчемся на месте. Так вот в принципе инженер может писать и на эссемблере и на кобыле (cobol), имея при определенном опыте неплохую продуктивность но это нисколько не означает что его программы будут более устойчивы к ошибкам, более читаемы, менее подвержены возникновению багов и поддерживаемость такого кода будет гораздо более сложной. Абсолютно такая же проблема возникает с java vs scala & c# vs f#. И еще проблема java в том что язык почти не развивается с релиза в6. Про JS я начал ради примера неверного использования подходов.
                                +1
                                Да не все так уж и сложно в Scala, если люди осилили Groovy, то проблем со скалой быть не должно — идеологически они весьма схожи
                                  +1
                                  Соглашусь что сакала нисколько не сложнее грува в освоении. Но не соглашусь с вами насчет идеологической схожести. При взгляде сверху они наверное схожи, наверное знаете как говорят Тюменская область по очертаниям похожа на Францию, больше на Францию она ничем не похожа. Груви задумывался как динамический скриптовый псевдо-язык а вот скала это строго типизированный язык, дальше больше.
                    0
                    Попробуйте аннотацию @CompileStatic к методам, раз вы все равно не используете динамику.
                      0
                      Ну совсем без динамики на Groovy — это хардкор :)
                      Без динамики Groovy теряет множество своих фишек.
                      Мы просто стараемся избегать лишней динамики, где это не нужно.
                      0
                      Как вариант кроме Scala можно было бы еще Flex/Air использовать: компилируемый, строгая типизация, есть байндинги, замыкания, хорошая поддержка в Idea, есть мощные визуальные компоненты для таблиц и окон, работы с удаленными сервисами etc.
                        +1
                        Это вы сейчас шутите или действительно советуете попробовать Flex/Air команде которая уже кучу лет разрабатывает IDE для Flex/Air?
                          0
                          А, сорри, не в курсе новых IDE для флекса. Это скорее были размыления о выборе сферической платформы для создания UI в космосе. Впрочем, «Eating your own dog food» было бы вполне уместно в данном случае. Почему бы не писать IDE для флекса на флексе? Не верю, что оно работало бы медленее чем на groovy. Если есть привязка к JVM, то я бы выбрал Scala — синтаксис схожий с groovy, а все-таки компилируемый и typesafe и куча продвинутых фреймворков.
                            +1
                            1) Groovy тоже компилируемый
                            2) Groovy тоже мягко говоря имеет кучу продвинутых фреймворков
                            3) AIR для IDE убог чуть более чем полностью. Поясню:
                            3.1) Нет наработанной базы кода для таких вещей как у JVM.
                            3.2) Сам язык (а пишу я на AS уже давно и много:)) очень слабый для таких вещей, отсутствие Generic-ов, типизированных лямбд, enum-ов, грамотных коллекций и ещё кучи всего
                            3.3) Работать будет очень медленно при таком объёме кода
                            3.4) Весь IO в AIR реализован на несколько порядков хуже JVM

                            4) по поводу Scala. Groovy — это better Java, можно писать старый добрый Java код, и периодически начинать использовать фишки Groovy. В Scala тебя сразу же с ходу заставляют писать монстра на непривычном синтаксисе. AFAIK в Scala такая конструкция не пройдёт (поправьте если я не прав):
                            onAction: { t ->
                                ProjectDialogs.newAsProjectDialog(scene, false)
                            } as EventHandler<ActionEvent>
                            
                              0
                              Насчет Groovy vs ActionScript убедили,
                              а насчет пункта 4: Scala is better Java too :)
                              На Scala можно писать в привычном для Java стиле, просто это быстро становится не нужно и неудобно.
                              В Скала тоже есть лямбда функции и блоки; каллбеки похоже выглядят. Их можно комбинировать, чейнить и пр.
                              см. например docs.scala-lang.org/overviews/core/futures.html
                                0
                                Если `onAction` — метод, принимающий `EventHandler[ActionEvent]`, то в Scala есть несколько способов организовать следующий синтаксис для вызова этого метода:

                                onAction { _ -> // здесь t заменили на _ чтоб подчеркнуть, что параметр не используется
                                    ProjectDialogs.newAsProjectDialog(scene, false)
                                }
                                


                                Тип указывать не надо, так как статически типизированный язык в курсе типов.
                                  0
                                  Ошибка. Естественно должно быть `=>`, а не `->`.
                                  +1
                                  Нашел интересную картинку: dou.ua/lenta/articles/language-rating-jan-2013/
                                  Индекс удовлетворенности языком — процент людей, которые работают на данном языке и выбрали бы его же в следующем своем проекте
                                  Scala — 0.85
                                  Groovy ~ 0.42
                                  Интересно от пользователей Груви услышать комментарии…
                            0
                            Примерно также можно еще на Kotlin'е. Тоже очень лаконично (можно и DSL еще более удобно читаемую сделать). Динамические методы чуть чуть по другому добавляются и еще некоторая разница по мелочи. Зато строгая типизация (типы в большинстве случаев автоматически выводятся).
                              0
                              Для того, чтобы язык пошел в люди, одного его мало… даже если он на JVM.
                              За груви есть Grails и Gradle, за Scala- akka, play, счас вот spray включили в typesafe stack.
                              А что есть у Kontlin?
                                0
                                У Kotlin есть все, что есть у Java и Scala — это раз. Тот же Netty, Akka и Spray пробовал использовать — все ок. Мы, например, Grizzly используем.

                                А так есть уже Kara (http://karaframework.com/), Wasabi (https://github.com/hhariri/wasabi/). Exposed (https://github.com/cheptsov/Exposed) и некоторые другие вещи. Плюс и своя стандартная библиотека потихоньку растет — уже много удобного.

                                Мы еще через несколько месяцев свой вариант над Grizzly опубликуем (особенно классно получились DSL для html и css — вдохновлялись у Kara, но сделали еще лучше).
                                  0
                                  Чтож, буду рад если взлетит… Хотя конкуренция большая. У Scala (см. ниже) — тоже есть недостатки. Но продвигают они технологию- курто. Посмотрите например на их typesafe.com/activator
                              +1
                              Недовно был сильно вдохновлен возможностями Scala, поучился у www.coursera.org/course/progfun, сделал небольшие приложения на play и spray. О плюсах не буду, их много и они очевидны. Хотелось бы узнать мения от профи на те трудности с которыми столкнулся:

                              1. SBT:
                              — sbt далеко не интуитивен.
                              — настороить по локальный репозиторий maven (чтоб не дублировать скачку, использую maven) не удалось.
                              — зависимость sbt и проекта от различных версий scala
                              — зачем на 1 модуль делать \target, \project\target и \project\project\target?

                              2. Scala
                              — местами сыровата (например наткнулся на баг работы с json github.com/playframework/playframework/issues/1189)
                              — чужой код (особенно фраймворковский) очень сложен для понимания
                              — очень плохо дебажится (особенно фраймворки)
                              — implicit фреймворка (например в spray) начинают в trait пересекаться с моими именами (например delete, get, create)
                              — обнаружил зависимость от порядка объяления в trait — моя ошибка при инициализации, но достаточно запрятанная
                              — уже совсем субъективно- specs2 в стремлении к сделать жизнь проще больше запутывает, чем помогает

                              3. Playframework-шаблоны (смесь javascript c синтакисом шаблонов play)
                              — IDEA никак не поможет в нахождении ошибки в javascript, т.к это не javascript
                              — никак не отдебажить из IDE по той же причине

                              Понимаю, что к некоторым отосбенностям (например sbt) надо просто привыкнуть, как обходятся с остальными?
                                0
                                Не профи, но хочу попытаться ответить на часть вопросов.

                                — sbt далеко не интуитивен.

                                Дело вкуса. Для меня он оказался наиболее интуитивным из всех систем сборки.

                                — зависимость sbt и проекта от различных версий scala

                                Можно взять нужную версию sbt. Можно указать версию sbt в файле `project/build.properties`.

                                — зачем на 1 модуль делать \target, \project\target и \project\project\target?

                                Конфигурация sbt — программа на scala. Со всеми теме же правилами для сборки. То есть сначала надо собрать конфигурацию, а потом собрать проект. Если для упрощения конфигурации требуется подключить сторонние библиотеки, то требуется конфигурация для конфигурации.
                                На мой взгляд весьма удобно, что не надо изучать отдельный не логичный язык для конфигурирования проекта и можно использовать тот же, что и для проекта.

                                — местами сыровата

                                Макросы еще не признаны стабильными, но их используют. Иногда бывают проблемы. Баги везде бывают. Этот проявился в период крайне бурного развития макросов.

                                — чужой код (особенно фраймворковский) очень сложен для понимания

                                Спорный вопрос. Зависит от опыта. Моего опыта уже хватает чтобы код playframework казался простым, логичным и понятным.

                                — обнаружил зависимость от порядка объяления в trait — моя ошибка при инициализации, но достаточно запрятанная

                                Порядок `val`? Куда же без него… Тема поднималась многократно и многократно разобрана. В качестве решения можно везде использовать lazy val, хотя это решение явно перебор.

                                JetBrains пилят поддержку playframework в IDEA. Не все же сразу.
                                  0
                                  Спасибо! Есть позиции которые с опытом уйдут. Есть — которые пилятся и уйдут. Одноко есть и те (например дебаг, множественный имплисит) которые- принципиальные.
                                    0
                                    По дебагу да, пока не очень радостно, хотя уже есть проекты, пытающиеся улучшить ситуацию (например вменяемое отображение стектрейсов). Честно говоря я пока по дебагу не скучал в scala — хватает покрытия тестами и конструкций Writer и Validation.

                                    Множественные implicit — тут обычная проблема конфликта имен. Я свои имплиситы называю пострашнее (в духе intIsNumeric). На мой взгляд delete, get и create в качестве имен имплиситов — явный косяк, достойный багрепорта.
                                0
                                Груви, напомню, кто не знает, позволяет обращаться к методам доступа (геттерам, сеттерам) без приставки set/get. То есть если в классе есть метод setText — то его вызов производится через простое присвоение значения — text = «Add». Плюс при компиляции Groovy классов, публичным полям добавляются геттеры и сеттеры автоматически. Поэтому из груви не прянято вызывать метод set/get если для этого нет реальной необходимости.


                                Достаточно спорно. Что если у меня в классе имеется 2 поля с именами Text и text? И для обоих нужены геттеры и сеттеры?

                                Да и геттеры\сеттеры по умолчанию для публичных полей… Смысл паблика как раз в том, что бы можно было на прямую получать к ним доступ (вопрос наследования опустим). Зачем оверхед, пусть и не большой?

                                Only users with full accounts can post comments. Log in, please.