- PVSM.RU - https://www.pvsm.ru -
Objective-C, по-моему мнение, — не очень удобный язык со множеством проблем. Но мы вынуждены писать приложения под iOS на этом языке. Я разработал другой язык, который генерирует код Objective-C. Поэтому в этом языке вы можете легко использовать классы Objective-C и C функции. Вы также легко можете использовать сгенерированные классы в коде Objective-C. Так что есть возможность вести разработку сразу на двух языках. Я назвал этот язык Objective-D.
Должен сказать, что это не законченный продукт. Я разрабатывал этот язык под свои нужды, поэтому в нем до сих пор много багов и недоработок. Разработку языка я вел на Haskell [1] и это был мой первый опыт работы с этим языком. Поэтому исходный код не очень хорош и его следует переработать.
За основу я взял синтаксис Scala [2], потому что Scala обладает очень компактным синтаксисом и мне это нравиться. Таким образом декларация класса получилось очень простой:
class Foo(bar : int) {
val baz = 1 //constant
var qux = 0 //mutable variable
def twiceBar = bar * 2 //function
}
Мне нравятся именованные параметры в Objective-C. Это повышает читаемость кода.
def foo(p1 : int, p2 : int) : int = p1 * p2
def bar = foo(p1 = 1, 2)
Однако, иногда имена параметров излишни, поэтому в Objective-D их можно опустить.
def foo(bar : int) = bar * 326
val bar = 1
foo(bar = bar)
foo(bar)
Эти классы нужны, чтобы можно было использовать Objective-C классы или C структуры в Objective-D. Они просто описывают методы и поля классов или структур.
stub class XMLElement {
def name : string
def text : string
def parent : XMLElement?
def children : [XMLElement]
}
Ужасно, что Objective-C не поддерживает дженерики и использует утиную типизацию [3]. В Objective-D я внедрил дженерики и использую статическую типизацию [4].
class Foo {
var array = MutableArray<Bar>()
}
Вы можете не указывать тип переменной или возвращаемое значение функции. Это может быть вычислено автоматически.
var i = 0
var i : int = 0 //тоже самое
Вы можете отнаследовать класс от одного класса и множества типажей, но типаж [5] — не простой интерфейс. Он может содержать поля и функции. Типаж только не может содержать конструкторы.
trait Foo {
def foo = 1
}
trait Bar {
var bar = 0
}
class Baz extends Foo with Bar
Вы можете определить структуры и функции внутри структуры. Структуры будут сгенерированы в C структуры, а функции в C функции.
struct Vec2(x : float, y : float) {
def dot(vec2 : Vec2) : float = x*vec2.x + y*vec2.y
}
В настоящее время это работает только со специальными названиями функций (add, sub, div, mul). Но я планирую реализовать следующее:
struct Vec2(x : float, y : float) {
def +(vec2 : Vec2) : float = Vec2(x + vec2.x, y + vec2.y)
}
Продемонстрирую синтаксис блоков на примерах:
def filter(predicate : T -> bool) : [T]
val array = [4, 3, 5, 1]
array.filter{item : int -> item > 3} // [4, 5]
array.filter{item -> item > 3 } // [4, 5]
array.filter(_ > 3) // [4, 5]
Тип данных item может быть вычислен по дженерикам, так что его можно не указывать.
Вы можете использовать встроенные выражения и переносы внутри строки. Посмотрите на пример:
val a = 1
val b = 2
val s = "a = $a
b = $b"
Кортежи могут быть очень полезны, чтобы объединить некоторые значение без декларации класса. Иногда их очень удобно использовать, как возращаемое значение функции.
val tuple = (1, "foo", "bar")
tuple.a == 1
tuple.b == "foo"
Эти значения будут вычислены только в момент первого обращения.
class Foo(bar : int) {
lazy val barSquare = bar * bar
}
Сопоставление с образом — большая тема в функциональном программировании. Это позволяет создавать более лаконичный и чистый код.
def foo(bar : (int, int)) : int = case(bar) {
(a, 1) -> a
(0, _) -> 1
_ -> 0
}
Мне нравятся перечисления в Java, поэтому я реализовал что-то похожее Objective-D.
enum Foo(bar : int) {
baz(1)
qux(2)
}
Отсутствии системы пакетов — большая проблема Objective-C, и мне совсем не нравятся префиксы классов.
package com.foo
import com.baz.ParticularClass
import com.bar._
Но префиксы необходимы в Objective-C, так что вы можете определить префикс пакета в Objective-D в пакетном объекте. Этот префикс будет добавлен к сгенерированным классам и файлам. В пакетном объекты вы также можете определить общие импорты для всех классов пакета.
package com
object foo {
import com.bar._
val prefix = "FOO"
}
Когда я начинал разрабатывать Raildale я использовал Cocos2D [6] и Objective-C. Позже я отказался от Cocos2D и перешел просто на OpenGL, так как я решил продолжить разработку. Если бы я использовал OpenGL с самого начала, я мог бы выбрать C++ вместо Objective-C.
Чере некоторое время после начала разработки я понял, что Objective-C начал меня раздражать. Первой проблемой стало, что там нет перечислений. Я имею ввиду перечесления со связанными свойствами как в Java или чего-нибудь, что могло бы это заменить. Я придумал несколько методов, как решить эту задачу, но все равно требовалось много кода. Я пробовал использовать макросы, но найти хорошее решение у меня так и не получилось.
И я решил разработать генератор кода для перечислений, что является нормально практикой в языко-ориентированном программировании. Это была первая часть Objective-D:
enum RailConnector(x : int, y : int, angle : int) {
left(-1, 0, 0)
bottom(0, -1, 90)
top(0, 1, 270)
right(1, 0, 180)
}
В качестве платформы для разработки генератора я выбирал из трех возможностей: JetBrains MPS [7], Scala [2] и Haskell [8]. Я выбрал Haskell, потому что там есть отличная библиотека для парсинга(Parsec [9]), и я не пробовал Haskell до этого. Должен сказать Haskell — прекрасный язык.
Я разработал перечисления очень быстро. И тут я подумал, что было бы здорово писать неизменяемые классы в простом лаконичном синтаксисе, и это несложно реализовать. И я разработал генератор для этого случая. Потом я добавил возможность писать простые функции в классах и продолжал добавлять фичи в процессе разработки Raildale. Также я разработал плагин для AppCode [10], которые подсвечивает синтаксис и позволяет делать некоторые простые рефакторинги. На разработку Objective-D к настоящему моменту я потратил 230 часов.
Я был бы рад, если бы кто-нибудь попробовал Objective-D, я помогу и постараюсь исправить возникающие у вас проблемы. Если кто-то захочет поучаствовать в разработке, буду очень рад.
$OBJD_HOME$/bin/ObjD
package test
class Foo(bar : int)
Вы можете также скачать плагин [12] для AppCode [10].
P.S. Это перевод моей же статьи с английского языка. Оформлял, это не как перевод, так как в правилах сайта сказано, что я не могу вставлять ссылки на свой сайт в статью, если она только не в блоге «Я пиарюсь». Спрашивал о такой ситуации у администрации сайта, ответа на запрос так и не получил. Так что ссылки решил не указывать.
Автор: Anthony
Источник [15]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios-development/53332
Ссылки в тексте:
[1] Haskell: http://www.haskell.org
[2] Scala: http://www.scala-lang.org/
[3] утиную типизацию: http://ru.wikipedia.org/wiki/Утиная_типизация
[4] статическую типизацию: http://ru.wikipedia.org/wiki/Статическая_типизация
[5] типаж: http://ru.wikipedia.org/wiki/Типаж_(абстрактный_тип)
[6] Cocos2D: http://cocos2d-iphone.org/
[7] JetBrains MPS: http://www.jetbrains.com/mps/
[8] Haskell: http://www.haskell.org/
[9] Parsec: http://book.realworldhaskell.org/read/using-parsec.html
[10] AppCode: http://www.jetbrains.com/objc/
[11] Скачайте Objective-D: https://github.com/antonzherdev/objd/releases
[12] скачать плагин: https://github.com/antonzherdev/objd-idea-plugin/releases
[13] Исходники: https://github.com/antonzherdev/objd
[14] Исходники плагина для AppCode: https://github.com/antonzherdev/objd-idea-plugin
[15] Источник: http://habrahabr.ru/post/209464/
Нажмите здесь для печати.