Буквально несколько дней назад компания Microsoft представила публике новый язык программирования. Языку дали название Bosque. Главная миссия дизайна языка — лучше быть богатым и здоровым, чем бедным и больным чтобы он был прост и понятен как для человека, так и для компьютера.



Информации пока что очень мало, язык еще очень свежий и нестабильный. Есть лишь paper от Марка Марона и дока в начальной стадии написания.


Давайте попробуем рассмотреть некоторые особенности языка.


1) Все значения в Bosque являются неизменяемыми (immutable), чтобы каждый блок кода не содержал никаких сайд-эффектов. По мнению авторов языка это полезно как для человека, так и для компьютера.


При этом, как ни странно, чуть далее по тексту рассказывается, что можно объявить изменяемую переменную ключевым словом var!. И это не просто сахар для более удобной инициализации иммутабельной переменной, это действительно настоящая переменная.


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


function internString(ref env: Map<String, Int>, str: String): Int {
    if(env.has(str)) {              //use the ref parameter
        return env.get(str);
    }

    env = env.add(str, env.size()); //update the ref parameter
    return env.size();
}

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


2) В языке нет циклов for, while и т.д. Вообще никаких нет. Вместо этого есть коллекции и пайплайны. Другими словами, вместо циклов нужно использовать более высокоуровневые штуки типа map, filter и т.д.


3) Строки можно делать разных типов. Т.е., например, можно сделать строку-имя или строку-zipcode, и для type-чекера это будут две разные строки. Если вы в аргументе функции ожидаете zipcode, а вам по ошибке туда пихают имя, то компилятор это не проглотит. Синтаксис такой: String[Zipcode].


Тоже сомнительная штука, почему не просто ZipCode. Один раз объявить, что ZipCode — это строка и везде в сигнатурах это писать. И почему именно для строк эта типизация сделана, а не для интов, например.


4) Вызов функций можно делать с указанием названия аргументов из сигнатуры функции, например: myfunc(x=1, y=2)


5) В стандартной библиотеке есть различные коллекции, и с коллекциями можно работать по разному. Можно просто по цепочке вызывать map, потом filter и т.д., а можно работать через пайплайны.


var v: List[Int?] = List@{1, 2, none, 4};

//Chained - List@{1, 4, 16}
v->filter(fn(x) => x != none)->map[Int](fn(x) => x*x)

//Piped none filter - List@{1, 4, 16}
v |> filter(fn(x) => x != none) |> map[Int](fn(x) => x*x)

//Piped with noneable filter - List@{1, 4, 16}
v |??> map[Int](fn(x) => x*x)

//Piped with none to result - List@{1, 4, none, 16}
v |?> map[Int](fn(x) => x*x)

6) рекурсия считается злом, которое может усложнить программу, поэтому рекурсивные фунции надо помечать словом rec


7) программы на Bosque являются детерминированными. Другими словами в языке нет неопределенного поведения. Например, нельзя использовать переменные, пока они не были определены; алгоритмы сортировки только стабильные и т.д. Если программа выдала какой-то результат, то такой же результат будет и потом, никаких сюрпризов


8) Вместо классов и интерфейсов в языке есть понятия entity и concept.


concept Bar {
    field f: Int;
}

entity Baz provides Bar {
    field g: Int;
    field h: Bool = true;
}

var y = Baz@{f=1, g=2, h=false}; //Create a Baz entity with the given field values
var x = Baz@{f=1, g=2};          //Create a Baz entity with default value for h

Пример кода


Вот крестики-нолики на Boscque
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

//
//This is a bosque test/benchmark for a tic-tac-toe program.
//

namespace NSMain;

entity Board {
    const playerX: String[PlayerMark] = 'x'#PlayerMark;
    const playerO: String[PlayerMark] = 'o'#PlayerMark;

    const allCellPositions: List[[Int, Int]] = List[[Int, Int]]@{
        @[ 0, 0 ], @[ 1, 0 ], @[ 2, 0 ],
        @[ 0, 1 ], @[ 1, 1 ], @[ 2, 1 ],
        @[ 0, 2 ], @[ 1, 2 ], @[ 2, 2 ]
    };

    const winPositionOptions: List[List[[Int, Int]]] = List[List[[Int, Int]]]@{
        List[[Int, Int]]@{ @[ 0, 0 ], @[ 0, 1 ], @[ 0, 2 ] },
        List[[Int, Int]]@{ @[ 0, 1 ], @[ 1, 1 ], @[ 2, 1 ] },
        List[[Int, Int]]@{ @[ 0, 2 ], @[ 1, 2 ], @[ 2, 2 ] },

        List[[Int, Int]]@{ @[ 0, 0 ], @[ 1, 0 ], @[ 2, 0 ] },
        List[[Int, Int]]@{ @[ 1, 0 ], @[ 1, 1 ], @[ 1, 2 ] },
        List[[Int, Int]]@{ @[ 2, 0 ], @[ 2, 1 ], @[ 2, 2 ] },

        List[[Int, Int]]@{ @[ 0, 0 ], @[ 1, 1 ], @[ 2, 2 ] },
        List[[Int, Int]]@{ @[ 0, 2 ], @[ 1, 1 ], @[ 2, 0 ] }
    };

    //Board is a list of marks, indexed by x,y coords from upper left 0 based
    field cells: List[String[PlayerMark]?];

    factory static createInitialBoard(): { cells: List[String[PlayerMark]?] } {
        return @{ cells=List[String[PlayerMark]?]::createOfSize(9, none) };
    }

    method getOpenCells(): List[[Int, Int]] {
        return Board::allCellPositions->filter(fn(pos: [Int, Int]): Bool => {
            return !this->isCellOccupied(pos[0], pos[1]);
        });
    }

    method getCellContents(x: Int, y: Int): String[PlayerMark]? 
        requires 0 <= x && x < 3 && 0 <= y && y < 3;
    {
        return this.cells->at(x + y * 3);
    }

    method isCellOccupied(x: Int, y: Int): Bool {
        return this->getCellContents(x, y) != none;
    }

    method isCellOccupiedWith(x: Int, y: Int, mark: String[PlayerMark]): Bool 
        requires mark == Board::playerX || mark == Board::playerO; 
    {
        return this->getCellContents(x, y) == mark;
    }

    method markCellWith(x: Int, y: Int, mark: String[PlayerMark]): Board 
        requires mark == Board::playerX || mark == Board::playerO;
        requires 0 <= x && x < 3 && 0 <= y && y < 3;
        requires !this->isCellOccupied(x, y);
    {
        return this<~(cells=this.cells->set(x + y * 3, mark));
    }

    hidden method checkSingleWinOption(opt: List[[Int, Int]], mark: String[PlayerMark]): Bool {
        return opt->all(fn(entry: [Int, Int]): Bool => this->isCellOccupiedWith(entry[0], entry[1], mark));
    }

    hidden method checkSingleWinner(mark: String[PlayerMark]): Bool {
        return Board::winPositionOptions->any(fn(opt: List[[Int, Int]]): Bool => this->checkSingleWinOption(opt, mark));
    }

    method checkForWinner(): String[PlayerMark]? {
        if(this->checkSingleWinner(Board::playerX)) {
            return Board::playerX;
        }
        elif(this->checkSingleWinner(Board::playerO)) {
            return Board::playerO;
        }
        else {
            return none;
        }
    }
}

entity Game {
    field winner: String[PlayerMark]? = none;
    field board: Board = Board@createInitialBoard();

    method hasWinner(): Bool {
        return this.winner != none;
    }

    method getWinner(): String[PlayerMark] 
        requires this->hasWinner();
    {
        return this.winner->as[String[PlayerMark]]();
    }

    method makeAutoMove(mark: String[PlayerMark], rnd: Int): Game
        requires !this->hasWinner();
    {
        var! nboard: Board;
        if(!this.board->isCellOccupied(1, 1)) {
            nboard = this.board->markCellWith(1, 1, mark);
        }
        else {
            var opts = this.board->getOpenCells();
            var tup = opts->uniform(rnd);
            nboard = this.board->markCellWith(...tup, mark);
        }

        return this<~( board=nboard, winner=nboard->checkForWinner() );
    }

    method makeExplicitMove(x: Int, y: Int, mark: String[PlayerMark]): Game 
        requires !this.board->isCellOccupied(x, y);
    {
        var nboard = this.board->markCellWith(x, y, mark);
        return this<~( board=nboard, winner=nboard->checkForWinner() );
    }
}

entity PlayerMark provides Parsable {
    field mark: String;

    override static tryParse(str: String): PlayerMark | None {
        return (str == "x" || str == "o") ? PlayerMark@{ mark=str } : none;
    }
}

entrypoint function main(): Game {
    var! game = Game@{};

    game = game->makeAutoMove(Board::playerX, 0);
    game = game->makeAutoMove(Board::playerO, 1);
    game = game->makeAutoMove(Board::playerX, 2);

    game = game->makeExplicitMove(2, 0, Board::playerO);
    game = game->makeExplicitMove(2, 1, Board::playerX);

    return game;
}

Итого


В общем, желаю языку удачи, конечно, но пока что Bosque выглядит странновато и сыровато. Скорее proof of concept. Причем, не совсем ясно, что именно является киллер-фичей. Документация порождает больше вопросов, чем ответов.


Компилятор для Bosque написан на Typescript, а не на самом языке, как это принято (например, компилятор Typescript написан на Typescript). Т.е. язык, скорее всего, еще недостаточно развит для написания более менее сложных программ.


В ближайшем выпуске подкаста "Цинковый прод" мы обязательно обсудим новый язык Bosque, возможно удастся собрать побольше информации. Так что не забудьте подписаться.

Комментарии (274)


  1. Anton23
    21.04.2019 20:51

    Может мне кто нибудь объяснить, почему компилятор для яп пишется на том же яп? На сколько я знаю, первый компилятор для TS был написан не на TS, и был написан только с одной целью — скомпилировать компилятор на TS. Так вот — это делается по идеологическим причинам или по каким то другим?


    1. varanio Автор
      21.04.2019 20:55
      +2

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


      1. Tangeman
        21.04.2019 21:24
        +2

        Если это традиция, то где же компиляторы (или хотя бы интерпретаторы) Perl на Perl, PHP на PHP, Ruby на Ruby или Python на Python?

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

        Задачи, к тому же, необязательно должны быть такими сложными во время разработки языка — к примеру, для отладки рекурсии хватит чисел Фибоначчи, для отладки многопоточности или асинхронной обработки — web-client/server.

        Но разумеется, если у разработчиков свободного времени вайлом — тогда да, почему бы и нет, собственно, пишут же эмулятор Z80 на bash


        1. splav_asv
          21.04.2019 21:48
          +1

          Ну, есть PyPy, есть PHPPHP.

          Для интерпретируемых языков больше характерна реализация на более низкоуровневом языке (C или C++, как правило). Или наличие трансляторов в C/Javascript.


        1. Deathik
          21.04.2019 21:52

          Так вы перечислили не компилируемые ЯП, если что. Они не самые быстрые, потому интерпретатор, как по мне, на том же языке писать — профита мало Да, за остальных не скажу, но есть у Питона — PyPy, можете почитать, ради интереса


        1. gatoazul
          21.04.2019 22:57
          +1

          Компилятор Perl6 написан на нем же.


        1. MechanicZelenyy
          22.04.2019 01:10

          Компилятор Python на Python, это уже упомянутый PyPy, который помимо того что следует традиции, ещё и предоставляет jit-оптимизации, и ускоряет программу в несколько раз.


          1. gudvinr
            22.04.2019 01:37
            +1

            Формально, PyPy — это не компилятор Python на Python.


            PyPy — это реализация интерпретатора Python на подмножестве языка RPython (валидный код на Python не обязательно является валидным для RPython).


            Сам PyPy написан на RPython, который уже является компилируемым языком. Но при этом компилятор RPython уже по большей части написан на Python.


            1. Aingis
              22.04.2019 12:13

              Картинка просто напрашивается:


        1. SeyranGV
          22.04.2019 07:00

          <шутка>а вы не задумывались над тем что эти люди просто научились писать в совершенстве компиляторы и больше не с чем заморачиваться не хотят <\шутка>


        1. nmrulin
          23.04.2019 14:28

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


      1. a0fs
        22.04.2019 00:45

        Компилятор — программа переводящая нечто написанное на неком языке в форму пригодную для исполнения на неком устройстве.

        — Машина работает с маш. кодами операций и аргументами в виде ячеек памяти и регистров.
        — Асемблер даёт имена маш. кодам и регистрам, делая их человекочитаемыми и наворачивает немного синтаксического сахара по оформлению операций. Но всё это приводимо к маш. кодам практически 1:1
        — С и иные системные языки — реализуют некоторые базовые конструкции алгоритмизации в своём синтаксисе, а также организуют среду программирования, состоящую из процедур и методов их написания. Что-то из данных процедур можно написать на асемблере и, используя соглашение о вызове процедур, внести её в среду программирования.
        И так далее. То есть язык более высокого уровня добавляет некоторое количество абстракций над языком более низкого, которые в основном представляют из себя просто часто повторяемые конструкции нижележащего языка приятно оформленные в некоторый синтаксис. Когда компилятор языка пишется на самом компилируемом языке возникает ощущение, что языка в этом месте быть и не должно. Возможно нужно спуститься ниже и переписать язык более низкого уровня. Компилятор может частично быть написан на своём языке, но ядро компилятора должно быть написано на языке, в который данный компилятор программу и перегоняет… По другому смысла в компиляторе не видно.

        И вообще это языковое безумие заставляет всё чаще вспоминать историю о Вавилонской башне если честно…


        1. juray
          22.04.2019 13:08

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


          1. vitvakatu
            22.04.2019 14:18

            Грань становится тоньше, когда вспоминаем про JIT-компиляторы, которые могут также по кусочкам в рантайме программу компилировать


            1. juray
              22.04.2019 21:57

              скорее, не тоньше, а размытее.


        1. domix32
          22.04.2019 13:30

          И вообще это языковое безумие заставляет всё чаще вспоминать историю о Вавилонской башне если честно

          Вот дозахватят нас роботы, тогда и bip bop bop bop bop bip bip bip bip bip bip bip bop bop bop bop bip bip bip bip bip bop bip bop bop bop bop bip bip bop bop bip bip bip bop bop bop bop bip bip bip bip bip bop bip bop bop bop bop bip bip bop bop bip bop bip bop bop bop bop bip bip bip bip bip bop bip bop bop bop bip bop bop bop bop bop bop bip bop bop bop bop bip bip bip bop bop bop bip bop bop bop bop bip bip bip bip bop bop


          1. Cerberuser
            22.04.2019 13:43

            А если будет восстание обезьян, тогда что? Ook! Ook.?


            1. domix32
              22.04.2019 22:31

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


              1. Cryvage
                23.04.2019 00:42

                Я бы не был так уверен


                1. matabili1973
                  23.04.2019 15:30

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


                  1. MTyrz
                    23.04.2019 19:08
                    +1

                    рано или поздно одна из них выиграет президентские выборы?
                    Пишущие машинки для этого совершенно излишни.


      1. gudvinr
        22.04.2019 01:28

        "Традиция" — это довольно сырой аргумент. Нужно понимать, что такие вещи делаются чтобы деньги зарабатывать напрямую, либо использовать наработки в других местах. Это ведь не Вася из 9 класса, который написал свой первый парсер и "потому что так принято" делать никто не будет.


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


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


        Вполне возможно, что через год-полтора сам язык торжественно передадут в сообщество (читай: забьют на разработку), а наиболее интересные решения войдут в TypeScript.


    1. splav_asv
      21.04.2019 21:10

      Еще два плюса:

      • Разработчики языка сами пишут на нём — хорошо для понимания проблем и развития языка.
      • Пользователям проще участвовать в разработке и в крайнем случае смотреть на детали реализации.


      Пример когда другой язык реализации мешает — Java. Отчасти поэтому сейчас есть проект VM на самой Java — GraalVM.


    1. some_x
      22.04.2019 07:52

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


      1. QtRoS
        22.04.2019 07:59
        +1

        Наверное все же "dogfooding"


        1. some_x
          22.04.2019 08:09

          Да, конечно! Спасибо, исправил.


      1. kzhyg
        22.04.2019 12:39
        +1

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


    1. Aquahawk
      22.04.2019 08:33

      Смотрите, вот файл из недр компилятора TypeScript github.com/Microsoft/TypeScript/blob/master/src/compiler/checker.ts 1.8 Мегабайта (!) одним куском. И его нельзя отрефакторить, потому что был использован module pattern который применяется в JS но абсолютно не имеет никакого смысла в TypeScript. И этот паттерн не расширяем. В итоге мы имеем 32К строк в одном файле? И 2624 вхождения слово function (из них большинство это действительно функции, а не комменты) И 462 стрелочных функции. И он растёт, и будет расти. Ещё в 2017 году я предпринимал попытки автоматизированными средствами это отрефакторить github.com/Microsoft/TypeScript/issues/17861 Ввиду нехватки времени на разработку предложенное решение имеет недостатки и проваливает производительность (я там бинжу все функции, а это не требуется в общем случае, но правильный детектор этого писать лень).

      Так вот, новые ЯП как правило нужны для введения и демонстрации новых техник программирования, ЯП никто не релизит ради синтаксиса. И есть концепция en.wikipedia.org/wiki/Eating_your_own_dog_food которая говорит что нужно использовать свой продукт. И вот вы как разработчик языка начинаете на нём писать его — же. Понимать как на самом деле работает то что вы придумали. В случае в TS изначальная архитектура пришла из старых JS подходов, и она откровенная слаба в TS мире. Вот поэтому я считаю что нужно писать ЯП на нём самом, не если это не DSL какой-нибудь.


      1. some_x
        22.04.2019 12:52

        А почему этот модуль нельзя разбить на несколько модулей поменьше + ещё один модуль который импортирует все функции из этих «чанков» и реэкспортирует их всех в виде неймспейса ts.


        1. Aquahawk
          22.04.2019 12:58

          Потому что в данном случае у этих функций огромный общий шареный стейт, что должно бы было быть свойствами объекта. Вот его часть

          Вот его кусок, но это не всё
           const compilerOptions = host.getCompilerOptions();
                  const languageVersion = getEmitScriptTarget(compilerOptions);
                  const moduleKind = getEmitModuleKind(compilerOptions);
                  const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions);
                  const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
                  const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes");
                  const strictBindCallApply = getStrictOptionValue(compilerOptions, "strictBindCallApply");
                  const strictPropertyInitialization = getStrictOptionValue(compilerOptions, "strictPropertyInitialization");
                  const noImplicitAny = getStrictOptionValue(compilerOptions, "noImplicitAny");
                  const noImplicitThis = getStrictOptionValue(compilerOptions, "noImplicitThis");
                  const keyofStringsOnly = !!compilerOptions.keyofStringsOnly;
                  const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : ObjectFlags.FreshLiteral;
          
                  const emitResolver = createResolver();
                  const nodeBuilder = createNodeBuilder();
          
                  const globals = createSymbolTable();
                  const undefinedSymbol = createSymbol(SymbolFlags.Property, "undefined" as __String);


          1. TheShock
            22.04.2019 13:13

            Что если все эти зависимости перенести в один объект. Вроде:

            const context = {
                compilerOptions: host.getCompilerOptions(),
                languageVersion: getEmitScriptTarget(compilerOptions),
                moduleKind: getEmitModuleKind(compilerOptions),
                // ...


            Во всем коде использовать этот объект как Service Locator, а потом начать передавать всем, кто его хочет как зависимость?


            1. Aquahawk
              22.04.2019 13:46

              Так я и делал в своём рефакторинге, я в том случае все свойства на this навесил и все методы пробиндил. И это даже тесты прошло полностью. Проблема в том что код стал ещё хуже и просел перформанс. А руками это сделать можно, ничего кроме объёма работы не мешает. Но сейчас никто не готов столько работы пожертвовать.


    1. impwx
      22.04.2019 10:39

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

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


    1. serge-phi
      22.04.2019 14:08

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


      1. Aquahawk
        22.04.2019 14:40

        Не сказал бы. Тьюринг полноты не достаточно для удобного программирования, и в то же время есть много не тьюринг полных DSL которые удобны. Как пример тьюринг полнота системы типов typescript github.com/Microsoft/TypeScript/issues/14833 вот ещё посмотрите ru.wikipedia.org/wiki/Тьюринговская_трясина


      1. tbl
        22.04.2019 19:31

        Вроде был язык, в котором только 3 функции, первая печатает "Hello world", вторая выводит текст программы, а третья генерирует компилятор этого языка. Так что возможность написать компилятор языка на самом языке не является доказательством полноты по Тьюрингу.


        1. TheShock
          22.04.2019 19:58

          1. juray
            22.04.2019 21:58

            только без генерации компилятора.


    1. worldmind
      22.04.2019 14:50
      +1

      Вот пишете вы на каком-то языке, растёте и в какой-то момент хотите в нем что-то улучшить/пофиксить и опа — оказывается что ваш 20 летний опыт разработки на этом языке тут не поможет, надо пойти ботанить какой-то другой язык на котором написан компилятор.


      1. Aquahawk
        22.04.2019 16:03

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


        1. worldmind
          22.04.2019 16:53

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


    1. 7aitsev
      23.04.2019 06:23

      Это называется Bootstrapping.


  1. NeoCode
    21.04.2019 21:07
    +5

    Как можно создавать язык программирования, не написав к нему документацию? Это уже не первый случай. Сначала накодят что-то, а потом задним числом сочиняют спецификацию.


    1. Tangeman
      21.04.2019 21:33

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

      Разница только в том что кто-то это делает публично, а кто-то «тайно» — в первом случае об отсутствии спецификации в начале разработки известно всем, а во втором об этом может никто и не узнать (поскольку её выложат вместе с языком) — хотя принципиальной разницы нет.

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


    1. impwx
      22.04.2019 10:29

      Встречный вопрос: какой смысл писать документацию к проекту в экспериментальной стадии, когда основные фичи еще обкатываются?


    1. dollar
      22.04.2019 13:37

      Сначала накодят что-то, а потом задним числом сочиняют спецификацию

      Называется Agile. И внезапно это удобно и эффективно, хотя и не везде.


  1. Tzimie
    21.04.2019 21:07

    Не в том ли идея чтобы он сразу мог бы параллелится?


    1. NotThatEasy
      22.04.2019 14:56

      Для упрощения этой задачи тут только иммутабельность, что само по себе не гарантирует хорошего паралеллизма.


      1. Tzimie
        22.04.2019 17:13

        Ну если нет циклов и идет работа со множествами то это напоминает SQL, который как раз располагает к паралеллизму…


        1. NotThatEasy
          22.04.2019 19:42

          Всё-таки давайте не будем смешивать в кучу язык общего назначения и SQL.

          Кстати, fun fact: Я был так много наслышан о том, как Хаскелл хорошо параллелится, ещё когда начал учить первый язык, что когда я схватился за Хаскелл, был поражён, что параллелить надо через монаду, что накладывает не одно ограничение на мой код, т.к. я ещё не понял их и трансформеры. Итог: не один десяток малых параллельных проектов на С++ и ни одного на Хаскелле.

          Вот тебе и «easy parallelism by design».


          1. Sirikid
            22.04.2019 20:22

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


          1. mayorovp
            22.04.2019 23:50

            А оператор `par` уже устарел?


            1. NotThatEasy
              23.04.2019 08:19

              Это и есть монада

              Ничего не устарело, просто я открыл для себя с изучением Хаскеля, что недостаточно просто «сказать» программе, что я хочу её раскидать на десять кластеров, а надо-таки раскидывать этот лёгкий-для-параллелизма из коробки по парам и секам.

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


              1. mayorovp
                23.04.2019 08:27

                Нет, это не монада.


                1. NotThatEasy
                  23.04.2019 14:45

                  Благодарю, загуглил сигнатуру, был сбит с толку другим результатом гугла.


              1. Tzimie
                23.04.2019 11:59

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


          1. 0xd34df00d
            24.04.2019 01:17

            Зачем там монады, если можно практически любой map заменить не думая на parMap rdeepseq?


            Есть, конечно, и монада Par, но она для чуть более сложных задач.


  1. maxzh83
    21.04.2019 21:13

    если мы можем передать Map по ссылке, и фунция ее намутирует.

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


  1. CheY
    21.04.2019 21:14
    +5

    Делаем простой и понятный язык для человека, поэтому добавляем побольше разномастных скобочек, стрелочек, знаков, двоеточий, точку с запятой в конце! *картинка с изображенеим genius*


    1. math_coder
      21.04.2019 21:38
      +6

      Да-да. На первый взгляд новый язык по читаемости может поспорить с Perl, J и триграфами C++.

      Мне кажется, я даже мгновенно перестал ненавидеть JavaScript после того как увидел это. Серьёзно, ещё пол-часа назад я хотел любыми силами избежать JavaScript в моей жизни, а сейчас JavaScript уже не кажется чем-то сильно плохим.


      1. cubit
        22.04.2019 13:51

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


    1. Balek
      21.04.2019 23:35

      Как вам удобнее читать формулировки теорем — в кванторах или в словах?


      1. CheY
        22.04.2019 01:26
        +2

        Слабая и неуместная аналогия. Мне удобен код с синтаксисом, который вызывает минимальную когнитивную нагрузку — моя голова и так будет загружена при чтении/написании кода. Здесь синтаксис, похоже, впитал всё самое жуткое из мира c/c++, так ещё и сверху присыпал от себя.


        1. Balek
          22.04.2019 11:00

          Если я правильно понял ваш первый комментарий, вы затронули сразу две темы — и визуальный шум, как точки с запятой, и специальные конструкции, как стрелочки. Насчёт шума я вас полностью поддерживаю. Но я хотел узнать именно про второе. Меня удивляет, что есть люди, предпочитающие писать «function», а не "=>". Пытаюсь понять причину.


          1. CheY
            22.04.2019 13:31

            Не, стрелочка в определении лямбд у меня нареканий не вызывает — это уже устоявшийся вариант.
            Я про другое. Если взглянуть на этот код, то можно увидеть следующие «интересности»:
            1) в классе (который назвали entity) есть const поля, а есть field. Казалось бы и то, и другое — поля класса, но к первым в коде обращаются через явное указание типа и двоеточия (Board::playerX), а ко второму через точку и this (this.cells). Нужно ли было делать такую разницу для данных в одной области видения?
            2) стрелочка используется и для вызова методов класса, и для пайпинга. Нет, конечно, можно подвести эти вещи под один знаменатель, если представить что каждый метод неявно принимает параметр this (вроде того, как это сделано в Питоне). Но нужно ли?
            3) потом мы видим, что через двоеточия мы по сути можем обращаемся к статическим const полям (game = game->makeAutoMove(Board::playerX, 0);). При этом само поле не помечено как static, хотя спецификатор этот есть (factory static createInitialBoard()). Кстати к этому статичному фабричному методу мы обращаемся уже через указание класса и собаку (field board: Board = Board@createInitialBoard();). Зачем надо было делать такое различие — не ясно.

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


          1. Spaceoddity
            23.04.2019 16:23

            Мне удобнее. Потому что function сразу бросается в глаза (особенно с подсветкой современных редакторов), заставляя заострить на этом куске кода внимание. "=>" же беглым взглядом вообще мало отличимо от оператора присваивания.
            Ну и вот, например, тут достаточно о разнице между function и "=>". Помимо того факта, что для этих стрелочек обычно надо ещё какой-нибудь Babel городить.


            1. mayorovp
              23.04.2019 17:10
              +1

              Там ровно два различия: свой this и свой arguments. Но если функции нужен свой this — то это никакая не функция, а метод; а для методов в свежем стандарте есть свой синтаксис. С arguments же всё ещё проще: надо перестать их использовать.


            1. veslemay
              24.04.2019 14:44

              (особенно с подсветкой современных редакторов),

              Скорее в древних блокнотах. Современный редактор умеет в семантическую подсветку. А подсветка уровня кейвордов — это про древний блокнот.

              Соответственно — function является лишним синтаксическим шумом, т.е. редактор умеет красить функции в уникальный цвет. И современно без разницы какие они.


        1. veslemay
          24.04.2019 07:11

          >> впитал всё самое жуткое из мира c/c++
          Что конкретно?


      1. daiver19
        22.04.2019 09:32

        На словах или в коде (в добавку к формулам). Очень часто тривиальные для понимания вещи прячут за вырвиглазными формулами с кучей нечитаемых переменных (речь про статьи по cs если что).


        1. Balek
          22.04.2019 10:47

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


  1. jevius
    21.04.2019 21:18
    +2

    Зачем?


    1. Alexey2005
      21.04.2019 21:46
      -1

      Это управленческий паттерн «незаменимая команда». Когда команда, разрабатывающая один из ключевых продуктов компании, переводит его на специально ими выдуманную технологию — новый язык программирования, принципиально новую СУБД с ни с чем не совместимым языком запросов, пишет с нуля новую ОС, на которой будет крутиться сервер продукта, ну и т.д.
      В итоге команда, которой удалось реализовать этот паттерн, надолго становится незаменимой — их становится очень сложно уволить, не завалив разрабатываемый продукт, потому что спецов по новой технологии в ближайшее десятилетие будет исчезающе мало.
      Именно поэтому программистам очень выгодно реализовывать этот паттерн. А вот для менеджера, допустившего такое, например переписывание половины браузера на принципиально новый язык — признак профнепригодности, особенно когда компания испытывает финансовые трудности.


      1. Paskin
        22.04.2019 08:10

        Это да, но самые упоротые — это «независимые консультанты». Во времена оны приходилось сталкиваться с персонажем, предлагавшим оптимизацию программ для (внимание!) «полного соответствия Ruby-way». Что самое удивительное — его даже кто-то нанимал…


    1. balsoft
      23.04.2019 00:29

      У всех остальных языков есть Фатальный© Недостаток™.


  1. TheShock
    21.04.2019 21:21
    +9

    Теперь мало того, что вместо вставления кода текстом — он вставлен картинками. Так мы теперь ещё и второй раз обливаем читателя дерьмом, используя для этого вместо моноширинного шрифта совершенно нечитабельный serif и блюрим картинку:



    Давайте вы её еще под углом сделаете и мигающей, вдруг ещё остались люди, которым удобно читать это уг?

    EDIT: Оказалось, что блурилось из-за масштабирования в браузере, но это всё-равно камень в огород автору статьи


    1. TheShock
      21.04.2019 21:24

      По идее если подсветить код как JavaScript — должно быть неплохо

      function internString(ref env: Map<String, Int>, str: String): Int {
          if(env.has(str)) {              //use the ref parameter
              return env.get(str);
          }
      
          env = env.add(str, env.size()); //update the ref parameter
          return env.size();
      }


    1. varanio Автор
      21.04.2019 21:28
      -1

      единственное место, где я нашел подсвеченный код — это pdf файл. Какой там шрифт есть, такой и есть.

      Можно разве что побольше сделать картинку, чтобы читалось получше


      1. varanio Автор
        21.04.2019 21:48
        -1

        в общем, я сделал шрифт побольше, но хабр зачем-то искажает размер картинки, поэтому замыленность всё равно есть


        1. Chaos_Optima
          22.04.2019 17:14

          А если просто переписать код его вроде немного? Ду ну бред какой-то.


          1. Cerberuser
            22.04.2019 17:53
            +1

            И вручную раскрасить? Или оставить равномерно чёрным, чтобы плевались теперь на это?


            1. Chaos_Optima
              23.04.2019 00:34

              Как выше уже продемонстрировали можно включить подсветку js, а так да, текст всегда лучше чем картинка с текстом, ну если только ты не капитан джек воробей.


  1. creker
    21.04.2019 21:53
    +3

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


    1. serf
      21.04.2019 22:04
      +2

      Вот вот. Среднему индусу в MS такое не осилисть.


      1. creker
        21.04.2019 22:12
        +2

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


    1. 0xd34df00d
      22.04.2019 04:22

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


    1. valis
      22.04.2019 13:05
      +1

      И чего в нем такого нового? Исследовательского?


  1. apxi
    21.04.2019 22:15
    +5

    Языки все больше становятся похожи на какие то клиновидные записи или древнеегипетские иероглифы ('x'#PlayerMark, =>, <~, Board::playerO, @, |>, |< и т.д. и т.п. в самых неожиданных местах) и не понятно зачем вместо превычного слова «class» и «struct» или «record», которые уже не одно десятилетие в других языках применяются, выдумывать что то новое. Вместо function вставили method, тогда вместо if нужно было еще что нибудь придумать, а еще лучше вообще язык поменять на русский, была бы еще одна 1С, только в функциональном стиле.


    1. DeuterideLitium6
      22.04.2019 00:01
      +1

      Вместо function вставили method

      Я так понял, что это означает, что функция виртуальная. Или нет?


      1. ksbes
        22.04.2019 11:40

        Ну в каком-то языке программирования (JS?) это может и так, но концептуально-то разница меду функцией и методом не такая. Лучше уж сделали бы как в С++ (virtual/override) или как в джаве — где всё виртуальное (зачем нужны невиртулаьные методы? — хороший вопрос для собеседования!)


        1. vics001
          22.04.2019 22:17
          -1

          Ответ: для того, чтобы всех запутать и после cast вызывался другой метод.
          Адепты С++ ответят, что тем самым экономят место в виртуальной таблице вызовов.


          1. 0xd34df00d
            24.04.2019 01:19

            Адепты C++ ответят, что тем самым, во-первых, легко получить классы без виртуальных методов вообще (что экономит место в лейауте класса и приводит к прочим приятным результатам на тему тривиальности типов), а, во-вторых, они облегчают работу девиртуализатору и инлайнеру (нечего девиртуализировать, если методы не виртуальные).


    1. assembled
      22.04.2019 09:50
      -1

      Языки все больше становятся похожи на какие то клиновидные записи или древнеегипетские иероглифы

      Ну почти все языки полны всяких «иероглифов», в заблуждение они вводят разве что новичков, со временем они запоминаются и проблем с их пониманием нет, конечно если не городить всяких заумных конструкций. Есть другая крайность — когда язык очень похож на естественный, как например SQL или COBOL, читать вербозный код не очень-то легко, а писать на таком языке вообще мрак и уныние.

      вместо if нужно было еще что нибудь придумать

      Ага, как в Red, if с одной ветвью, either — с двумя.


      1. worldmind
        22.04.2019 14:57

        if с одной ветвью, either — с двумя.

        Хм, на первый взгляд крутая идея


    1. Lamaster
      22.04.2019 10:39

      > тогда вместо if нужно было еще что нибудь придумать
      whatever(false condition)


    1. mihmig
      22.04.2019 10:52

      а еще лучше вообще язык поменять на русский

      Тсс, тихо! А то ещё призовёте дьявола в 1С 8.4 в виде:

      #РасходнаяНакладная^Conclude(СуммаСовсемБез НДС).Подобно()


      1. KvanTTT
        22.04.2019 11:12

        «Подобно» или все же «Подробно»?


        1. extempl
          22.04.2019 14:52

          А мне интересно что такое Conclude и почему не на русском? Внешняя команда или…?


  1. AndreySitaev
    21.04.2019 22:19
    +1

    программы на Bosque являются детерминированными… Если программа выдала какой-то результат, то такой же результат будет и потом, никаких сюрпризов


    Вот эта формулировка меня очень и очень смущает. То есть… скажем, если программа использует БПСЧ… или обращается к жесткому диску / сетевому адресу… результатом будет синий экран?

    Или вот это:
    алгоритмы сортировки только стабильные


    под стабильными, наверное, понимаются устойчивые алгоритмы? А если я напишу на Bosque алгоритм Шелла (неустойчивый) — будет исключение рантайм? Ошибка компиляции?

    Поясните, пожалуйста. Взрывает мозг…


    1. varanio Автор
      21.04.2019 22:23

      Дословно в документации так:

      Thus, Bosque does not have any undefined behavior such as allowing uninitialized variable reads and eliminates all under defined behavior as well including sorting stability and all associative collections (sets and maps) have a fixed and stable enumeration order.

      As a result of these design choices there is always a single unique and canonical result for any Bosque program. This means that developers will never see intermittent production failures or flaky unit-tests!

      Больше информации нет никакой.

      Возможно, я что-то не так понял. Готов исправить статью


    1. jaiprakash
      22.04.2019 00:25

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


      1. Paskin
        22.04.2019 08:12
        -4

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


        1. jaiprakash
          22.04.2019 11:34

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


        1. 0xd34df00d
          22.04.2019 15:51

          Нет. Отсутствие UB можно доказывать индуктивно и, как следствие, линейно или квадратично по числу правил вывода типов (см. Featherweight Java, например).


      1. assembled
        22.04.2019 09:56

        Вот если появится вторая реализация, появятся и UB.


        1. mayorovp
          22.04.2019 10:53

          UB может появляться и без второй реализации.


  1. DeuterideLitium6
    21.04.2019 23:51

    Непонятно, какие преимущество у этого ЯП по сравнению с другими? Тем же С++.
    Вот мне нужен ЯП, смесь из ассемблера(доступ к флагам и регистрам процессора), С и С++(классы, виртуальные функции) и при этом достаточно простой. Думаю развивать идею ассемблера MASM'а(UASM), кодогенерирующие макросы .if, .while, .for, и т.п.
    А по этому ЯП(назовём его Боська), в упор не вижу каких либо достоинств. Да, у меня память не очень хорошая, и очень не хочется её перегружать лишней инфой, изучая кучу очень сложных ЯП. Надо проще делать, чтобы простой как Lua и достаточно функциональный как С++.


    1. Paskin
      22.04.2019 08:18

      КО подсказывает, что в С/С++-программы можно делать ассемблерные вставки, использовать intrinsics или линковать к ним модули на ассемблере.


    1. Bronx
      23.04.2019 08:32

      назовём его Боська

      Назовём его Босх.


    1. nmrulin
      23.04.2019 20:29

      Уже есть такой язык — Паскаль. И прост(не зря школьникам преподают) и функционален.


  1. Terras
    22.04.2019 00:38
    -1

    del


  1. wtpltd
    22.04.2019 01:25

    В статье почему-то не упомянуто, что это от команды MS Research. Т.е. пока просто какой-то эксперимент. Что-то попробовать и посмотреть, что из этого может получиться.
    Поэтому, обсуждать можно какие-то моменты, с учетом того, что все может поменяться раз и на 180. А может и вообще сгинуть. Или какие-то фичи где-то прикрутят.
    А так-то чего бы не написать в заголовке «MS представил общественности убйцу C#»


    1. varanio Автор
      22.04.2019 06:56
      -1

      И что, что от MS Research? Понятно, что не от MS Office. И в заголовке, кстати, нет ровно никакой желтизны.

      Поясните свою мысль.


      1. Ogra
        22.04.2019 14:51
        +1

        Ну от MS Research или от MS Developer Division — огромная разница.
        Желтизна сегодня — она именно такая. Написать абсолютную правду, но так, чтобы сформировать ложное впечатление. «Новый язык от Microsoft» — это явно про какой-то продукт, который распространяет компания Microsoft. Не эксперимент в Research, а конкретный продукт с поддержкой в Visual Studio.


        1. varanio Автор
          22.04.2019 14:54

          Я не в курсе про MS Developer Division и т.д. Поэтому и попросил пояснить мысль.


          1. Newbilius
            22.04.2019 18:03

            Так может быть вам как автору новости стоило бы всё выяснить, прежде чем торопиться писать?)


            1. varanio Автор
              22.04.2019 18:27
              -2

              Выяснить всю структуру Microsoft?
              Если бы я знал о таких нюансах, я бы конечно выяснил.


              1. Ogra
                22.04.2019 19:27

                Хотя бы выяснить, что такое Microsoft Research, и какими проектами они занимаются? Тяп-ляп и в продакшен, да?


                1. varanio Автор
                  23.04.2019 07:54
                  -1

                  Самоутверждаетесь в комментариях, да?


              1. Yanis
                23.04.2019 06:18

                В readme репозитория, на который вы даёте ссылку в начале «статьи», как раз и говорится, что язык Bosque это проект Microsoft Research и приводится ссылка на него. «Выяснить структуру Microsoft» не обязательно — вся информация не дальше первых ссылок поисковой выдачи. Это не так уж и сложно, если решили выложить некий обзор. Абзац с подведением итогов говорит о том, что вы действительно не разобрались что этот проект ни что иное как PoC.


  1. devpony
    22.04.2019 01:41
    +2

    Выглядит как первоапрельская шутка.


    1. mapron
      22.04.2019 06:03

      «Весь апрель — никому не верь!»


    1. vlreshet
      22.04.2019 09:49

      А я думал я один трижды проверил дату пока дочитал пост


  1. KvanTTT
    22.04.2019 02:08

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

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


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

    Почему? Многие алгоритмы наоборот в рекурсивном виде выглядят просто и естественно. А нерекурсивный вариант выглядит куда более громоздко.


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


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

    Какие-нибудь современные языки являются недетерминированными? Вспоминается только C++. Записывать это в плюсы — все равно что писать, что в языке можно использовать не латинские идентификаторы.


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

    Что это за чушь вообще. А что если используется функция генерации случайных чисел?


    Также хочется задать авторам вопрос: чем их не устроил собственный же язык F#?


    1. TheShock
      22.04.2019 02:21

      Также хочется задать авторам вопрос: чем их не устроил собственный же язык F#?
      NIH в масштабе локальной команды?


    1. MacIn
      22.04.2019 16:36

      Для компьютера лучше всего понятен ассемблер.

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


    1. Source
      23.04.2019 21:01

      чем их не устроил собственный же язык F#?

      Тоже возник такой вопрос. А вообще лучше бы они Nemerle поддержали.


    1. nmrulin
      23.04.2019 22:24

      " чем их не устроил собственный же язык F#" Это теперь у всех такое поветрие — яростно пропихивать свою поделку, потом сами же забрасывать. Как ябочники вместо C++ зачем-то пропихивал objective-c, потом сами же его и забросили.


    1. Witch-hunter
      23.04.2019 22:27

      F# слишком сложен, он вдвое сложнее C#, а С# сам по себе непрост, у МС нет собственного простого языка (VB.NET не в счёт) а-ля Python/Go/PHP. Нужен простой, чтобы его можно было в школах преподавать.


      1. 0xd34df00d
        24.04.2019 01:24
        +1

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


        1. Cerberuser
          24.04.2019 05:39

          Видимо, .net имеет такую же сложность, как и функциональный стиль, соответственно, их сочетание сложность удваивает.


        1. Witch-hunter
          24.04.2019 06:57

          Так же, как я определяю, что одна книга вдвое толще другой: по количеству нового материала. Книга F# for fun and profit имеет аж 1930 страниц! F# может почти всё, что может С# плюс вдвое больше. Учитывая, что помимо самого языка нужно еще изучить функциональную парадигму программирования, привыкнуть к новому синтаксису, получается не проще, чем еще раз прочесть книгу по С# + GoF. Понятное дело, что инженеры, научные работники, а так же школьники, студенты, хипстеры и стартаперы не являются целевой аудиторий F#.


          1. Sirikid
            24.04.2019 08:06

            Знаете, не все были искалечены ООЯП в процессе начального обучения программированию, кто-то начинал с функционального или даже логического языка.


            1. Witch-hunter
              24.04.2019 08:43

              F# гибридный язык, так что рискнувшему его изучить придется «запачкать ноги».


            1. 0xd34df00d
              24.04.2019 22:45

              Я как-то случайно наблюдал, как человек (причём совершенно не технарь) первым языком учил JS… В общем, было видно, что equational reasoning человеку куда ближе и милее, чем вся ОО или вообще императивная парадигма.


            1. juray
              25.04.2019 12:45

              а кто-то вообще с релейных диаграмм


  1. assembled
    22.04.2019 06:35

    Я не понял, сперва говорится об иммутабельных значениях, а потом о возможности объявления мутабельных переменных. Так что всё-таки иммутабельно, значения или переменные?

    Вместо классов и интерфейсов в языке есть понятия entity и concept.

    Но это те же интерфейсы и классы, просто названы по-другому.


    1. Cerberuser
      22.04.2019 06:57

      В такой формулировке это звучит как утверждение, что присвоить переменной новое значение можно, а вот никакой внутренней мутабельности уже нет — если нужно заменить значение поля в объекте, изволь менять весь объект, как-то так…


  1. Gymmasssorla
    22.04.2019 07:28

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

    Какая же инновационная идея появилась у Microsoft, никто до этого раньше даже и не додумывался.


  1. untilx
    22.04.2019 08:05

    M$ изобрели Erlang только TypeScript


  1. IvanNochnoy
    22.04.2019 09:30

    Пока это всего лишь эксперимент, и, возможно, этот проект ждёт та же печальная судьба, что и Code Contracts.


  1. rpiontik
    22.04.2019 09:51

    Че-то я не осознал цели этого творения. Если крупная компания выводит на общее обозрение нечто, пусть и не в форме релиза, но под своим именем, она чего-то ждет. Языки имеют специализацию. А тут я че-то ничего внятного не нашел.
    Хотя… возможно, это очередная попытка от MS создать Java.


    1. iluxa1810
      22.04.2019 12:33

      А зачем MS создавать еще один Java?

      Разве MS не создала свое виденье Java создав C#?


      1. rpiontik
        22.04.2019 12:57
        -3

        Именно. И проект, в общем-то оказался провальным. Можно сколько угодно обсуждать спешность шарпа, но его удел оказался корпоративные решения. А прибитость его к .net вообще не ясна, потому, что никакой крос-платформенности он не дает. В общем, как по мне, так акая-то хрень вышла. Как и VB до этого. Который MS сует куда не попадя, даже в свои браузеры совала. Сравнивать его с Java язык не поворачивается.


        1. Ogra
          22.04.2019 14:52
          +1

          корпоративные решения… никакой крос-платформенности

          Вы что-нибудь слышали про Unity?


        1. Alexsey
          22.04.2019 15:10

          А прибитость его к .net вообще не ясна, потому, что никакой крос-платформенности он не дает.


          Я просто оставлю это здесь
          image


          1. rpiontik
            22.04.2019 16:56
            -1

            Я тоже, просто оставлю это тут.

            Несмотря на существование Mono, C# тесно привязывает разработчиков к платформе Microsoft (включая ОС, офисные решения). Таким образом, пользователь программного обеспечения, написанного на .NET, часто не имеет выбора в использовании различных компонент системы. Это приводит к так называемому vendor-locking, при котором производитель стороннего ПО может диктовать покупателю практически любые условия на поддержку внедрённого проекта. В то время, как пользователь приложения Java, как правило, может сам выбрать поставщика дополнительного ПО (такого, как БД, ОС, сервера приложений и т. д.).


            Это указано на вики. И копипастю сюда не как пруф, а как текс с которым Я согласен. И имею то же мнение.

            К кросплатформенности я отношу не просто исполнение кода на чем-то ином, а развитую экосистему продукта, адаптированную под платформу. MS же тянет все свое с собой. И… пфффф… Ну и повторюсь еще раз — это лишь мое мнение.


            1. creker
              22.04.2019 18:24
              +2

              С такой точки зрения java такой же vendor-lock, т.к. стандартное явление видеть программистов, которые живут энтерпразйным java стеком и всю жизнь за его пределы не вылазят, что их даже на работу не взять себе для чего-то другого.

              А в общем, вы процитировали глупость, с которой согласны лишь потому, что не имеете представления о ситуации так же как ее не имеет автор этого опуса. Кроме этого вашего mono вообще-то есть .net core.


            1. kasthack_phoenix
              22.04.2019 18:46
              +1

              это лишь мое мнение.

              Оно какими-нибудь фактами подкреплено? На прошлых двух работах писал на дотнете совсем не под windows — мобильная разработка на Xamarin(Android, iOS) и тяжелый бэк на .NET Core(Linux) — есть вполне конкретные контрпримеры к утверждению, что оно прибито к MS-экосистеме / кроссплатформенность недостаточного качества для энтерпрайза.


              К кросплатформенности я отношу не просто исполнение кода на чем-то ином, а развитую экосистему продукта, адаптированную под платформу. MS же тянет все свое с собой

              nuget? Если взять топ-100 пакетов оттуда по популярности(не стал проверять дальше), все они работают на *nix без проблем.


              1. rpiontik
                22.04.2019 20:56
                -2

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

                Подкреплено личным опытом, в период с момента его первого релиза до 2014г.


                1. Alexsey
                  22.04.2019 23:06
                  +1

                  Подкреплено личным опытом, в период с момента его первого релиза до 2014г.


                  Слушайте, ну вы вроде как тим лид, да еще и с таким большим опытом работы с .net. Кому как не вам понимать что за 5 лет в современной индустрии меняется вообще все и ваш опыт .net пятилетней давности имеет мало общего с тем что мы имеем в 2019 году.


                  1. rpiontik
                    23.04.2019 07:31
                    -1

                    Или… или как тимлид с некоторым опытом, который наблюдал многострадания MS подвинуть Java, а еще и Delphi (че к нему то привязались, вообще не ясно) одним махом. При этом, завезя все, что было в VB и прибив гвоздями к своему любимому OLE. Наблюдая конвульсии шарпа с первой презентации (с криками — долой самодержавие Java!) до отказа от всех внедрений на нем в крупных компаниях и переход на Oracle.
                    Я таки (за 10 лет) сложил свое мнение и об языке и о его перспективах и сделал свой выбор, в свое время. И ни разу о нем не пожалел.


                    Вот как завезут .net на хотя бы 30% устройств как предустановленную машину, так и поговорим. А то в свое время визгу было, что мир теперь изменится, про java забудут и везде будет .net. А я как отъехал от MS так за все время, даже случайно не встретил .net на чем-то отличном от винды.


                    1. mayorovp
                      23.04.2019 08:31
                      -1

                      До наступления эпохи смартфонов .net как раз и был предустановлен более чем на 30% устройств.

                      А на смартфонах предустановленный .net и не нужен: mono прекрасно распространяется вместе с приложением.


                      1. rpiontik
                        23.04.2019 08:49
                        -1

                        До наступление эпохи смартфонов была эпоха динозавров, когда ничто кроме MS не было. Даже на IE 6.0 VB работал как скриптовый язык. И MS пыталась «подскочить» в уезжающий без нее поезд компактных устройств. Напомню, что MS запилила WinCE и WindowsMobile где .net устанавливалась. Ну и где оно? Это невмеру прогрессивное архитектурное и инженерное решение?

                        Ровно также, как только появилась Java, тут же скукожилось и съехало в небытие. Причем скукоживаться начало уже тогда, когда простые мидлеты появились на простых телефонах. Заметьте не .net, а Java машина туда ставилась. Почему бы?

                        С выходом первого андройда WindowsMobile был приговорен. Вялые попытки что-то там пропихнуть через покупку Nokia увенчались тоже полным крахом. Сейчас MS приторговывает… Nokia 3110 (или какого они там мамонта возродили) в оригинальном исполнении. Смешно? По мне так очень.

                        А на смартфонах предустановленный .net и не нужен: mono прекрасно распространяется вместе с приложением.


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


                    1. IvanNochnoy
                      23.04.2019 09:31
                      +1

                      Реальная ситуация здесь:
                      Developer Survey Results 2019


                      1. rpiontik
                        23.04.2019 09:40

                        Занимательная ссылка (y)


              1. TheKnight
                23.04.2019 01:29

                и тяжелый бэк на .NET Core(Linux)

                Не вброса ради а любопытства для: в качестве ОС для разработчика на этом проекте вы использовали Windows или таки Linux?


                1. kasthack_phoenix
                  23.04.2019 17:36

                  Windows — до VS кроссплатформенным IDE не дотянуться ещё.


                  IIRC, ни в Rider, ни в VSCode, ни даже в Monodevelop a.k.a Xamarin Studio a.k.a VS for Mac нет edit-and-continue до сих пор.


                  1. KvanTTT
                    23.04.2019 21:41

                    В Rider уже есть, скоро будет в стабильном релизе: www.jetbrains.com/rider/eap


        1. LMSn
          22.04.2019 15:20
          +1

          В общем, как по мне, так акая-то хрень вышла.

          Какая-то аргументированная критика C# в сравнении с Java у вас есть?
          Именно. И проект, в общем-то оказался провальным.

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


          1. TheShock
            22.04.2019 15:32

            Какая-то аргументированная критика C# в сравнении с Java у вас есть?
            Лично я скажу, что в Шарпах в сравнении с Джавами просто прекрасные Дженерики


            1. varanio Автор
              22.04.2019 15:35

              А в чем отличие, можете в двух словах рассказать?


              1. TheShock
                22.04.2019 15:39

                var text  = GetComponent<Text>();
                var image = GetComponent<Image>();
                

                В Java невозможно так сделать — информация о дженериках теряется на этапе компиляции и этот код скомпилируется во что-то такое:
                Text  text  = GetComponent();
                Image image = GetComponent();
                

                Естественно, работать не будет. В Шарпах информация о типах сохраняется и её можно использовать не только как подсказки, но и в коде.


                1. mayorovp
                  22.04.2019 15:43

                  Вот это как раз без особых проблем работает, просто вместо угловых скобок надо использовать class:


                  Text text = GetComponent(Text.class);
                  Image image = GetComponent(Image.class);


                  1. TheShock
                    22.04.2019 15:46

                    Да я понимаю, что можно без этого. В Go вон вообще без дженериков обходятся как-то. Просто это менее удобно.


                    1. mayorovp
                      22.04.2019 15:55

                      Тут всего-то на 4 символа больше писать надо, это совсем не то же самое что и «без дженериков». Если сравнивать с тем как в Java «реализованы» свойства — то эти 4 символа и вовсе незаметны.


                      1. TheShock
                        22.04.2019 16:25

                        Мне оно не шибко нравится не по количеству символов, а по сути.
                        Да и это не единственный пример, где то, что дженерики пропадают на этапе компиляции — мешает


              1. mayorovp
                22.04.2019 15:41

                В том, что они не пропадают во время исполнения. Отсюда два следствия:

                1. статические поля и методы также могут использовать типы-параметры;
                2. можно без хитрых извращений и без тонн автогенерированного кода взять и использовать контейнер, параметризованный примитивным типом.


                1. TheShock
                  22.04.2019 15:48

                  2. Вы о том, что в Java список может принимать только Boxed Integer, но не примитивный int?


                  1. mayorovp
                    22.04.2019 15:53

                    Ага, именно об этом. Соответственно, или мириться с постоянными упаковками, которые никакой Escape analysis не уберёт по построению — или использовать отдельный интерфейс и отдельную реализацию для списка чисел.


          1. rpiontik
            22.04.2019 16:49
            -1

            Вы мне еще мнение запретите высказывать :))) Смешно.


  1. impwx
    22.04.2019 10:34

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


  1. Livid
    22.04.2019 10:40
    +2

    String[ZipCode]

    Чего только люди ни придумают лишь бы не делать алгебраические типы…


    Вообще конечно выглядит пока сомнительно. Особенно комбинация заявленной иммутабельности с ref — то ли авторы сами толком не определились, чего они хотят от языка, то ли не очень понимают, что immutability это совсем не то, что делает const в javascript. Вообще изрядно отдаёт какой-то фиксацией на javascript-е. Как будто авторы даже с наработками "родного" майкрософтовского F# не вполне знакомы, хотя пайп |> явно оттуда потянули.


  1. mihmig
    22.04.2019 11:04

    Хм, а мне понравился отказ от циклов в пользу перебирающих методов. Ведь при работе с коллекциями обычно требуется их отфильтровать либо агрегировать. Школьные задачки типа «посчитать количество чётных чисел в массиве, стоящих на нечётных местах» в расчёт не берём — задача синтетическая и рассчитана как раз на понимание циклов.


    1. mayorovp
      22.04.2019 11:17

      А у меня довольно часто встречаются задачи, в которых простейший цикл выглядит проще чем комбинация фильтров. Как правило, это задачи вида map + filter + map, где из первого map нужно «прокинуть» в последний исходный объект, который при этом совершенно не нужен в фильтре. Особенно плохо всё становится, когда в ходе изменения требований необходимость этого объекта в конце цепочки то появляется, то исчезает.


      1. Cerberuser
        22.04.2019 11:27
        +1

        К слову, один из таких случаев — когда последний map должен знать номера объектов в исходном (неотфильтрованном) списке.


        1. lgorSL
          22.04.2019 13:17

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


          1. Cerberuser
            22.04.2019 13:24

            Так об этом и речь: object -> {map} -> (object, index) -> {filter} -> (object, index) -> {map} -> object_processed_with_index.


            1. Flammar
              23.04.2019 13:37

              Тогда начать можно со списка индексов, хотя это выглядит не вполне красиво. Я так делал с GUAVA c использованием Lists.transform(new AbstractList(){...}, ...).


          1. Flammar
            23.04.2019 13:35

            Ну я тоже так делаю, но мне это напоминает «строительство клозуры (=замыкания) вручную». Не особо элегантно.


    1. Source
      23.04.2019 21:12

      Меня несколько смущает, что ничего не сказано про ленивость вычислений. Если уж отказываться от циклов, то это must have.


  1. Escalibur
    22.04.2019 12:11

    Я тут написал статью, где были подвергнуты критике две любимые концепции нынешнего ИТ — очередь и стек.

    Так же была описана концепция OS BlockOut (разработанная в 1995), где все процессы организованы в сети процессов, обменивающихся сообщениями. Входами сетей являются внешние события, выходами — выходные устройства. Сети передают сообщения без буферизации, то есть размер очередит всегда == 1, соответственно, никогда нет рекурсий, то есть стек не нужен.

    Статья была перенесена в черновики, так как столкнулся с «хабраэффектом», а именно, травле по принципу «белая ворона» в стае чёрных. Попытки аргументированных споров были, но минимум. Большая часть аргументов была в стиле: «ты — дебил». Соответственно, всё это сопровождалось минусованием и невозможностью нормальной дискуссии по правилам размещения сообщений.

    Что мы видим в данном языке: та же попытка сетей процессов, обменивающихся сообщениями которые идут по каналам. То есть моя концепция 1995-го года.

    Далее, есть ещё одна тема, которая вызовет у любителей современного состояния ИТ страшное раздражение. На эту тему я ещё статей не писал. Это необходимость исключения высокоуровнего императивного программирования и тотальный переход на декларативное. Только эта парадигма позволит нормализовать ситуацию с качеством ПО, так как даст возможность создавать программы, которые позволяют проверку на корректность и смогут избегать дурацких ошибок императивного стиля. Так же, несомненно, это позволит как автоматизировать производство ПО, так и повысить продуктивность разработки.

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

    Таким образом, данный язык — несомненно шаг вперёд, но, скорее всего, он далее лабораторий МС не пойдёт, как многие хорошие вещи, которые там разрабатывались, к примеру Singularity.


    1. Escalibur
      22.04.2019 13:31
      -2

      Два минуса и как обычно без объяснений )) Люблю хабр! Товарищи, обосновать не хотите? Так-то это хамство. И то, что вам это позволяют авторы сайта, не означает, что вы так себя можете вести!


    1. mayorovp
      22.04.2019 13:38

      Не вижу в этом языке никаких процессов и каналов. Pipe operator только называется так, а дальше коллекций дело не уходит.

      За процессами и каналами — в go, в Erlang, или в Java и её библиотеку Akka, или в .NET и в библиотеку Akka.NET. Но там очереди, почему-то, есть. Как и стек. Не согласна почему-то реальность с вашими фантазиями…


      1. Escalibur
        22.04.2019 15:58
        -2

        Коллекции + map reduce хочу заметить. А этими парадигмами закрывается львиная доля задач.

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


        1. mayorovp
          22.04.2019 16:02

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


          1. Escalibur
            23.04.2019 05:51

            У меня один простой вопрос к любителям очередей: а зачем?

            Опять же практически процитирую сам себя:

            Очередь — это буфер. То есть мы пихаем в буфер некие элементы в надежде на что? Я так понимаю на то, что у нас сейчас заняты некие ресурсы и мы надеемся, что они в какой-то момент освободятся и мы сумеем обработать то, что набилось в очередь.

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

            На первый вопрос ответ понятен: просто не умеем нормально проектировать. В результате, к примеру, лунные модули не садятся на Луну. Но это то, что видно, а бОльшая часть косяков, связанных с неправильной оценкой производительности, не видна, так как системы не настолько критические. Единственно, что я могу признать как вариант нормального использования очереди — это выравнивание пиков нагрузки. Но тогда очереди должны быть хотя бы ограничены по ёмкости. То есть мы должны осознавать какую нагрузку мы должны принять и выравнять.

            Про второй вариант ответ так же прост: мы просто сбросим содержимое очереди. Дак зачем копить очередь, занимая ресурсы, если можно сбрасывать элементы сразу? Зачем ждать, пока клавиатура запищит от переполнения буфера, если можно просто до него не доводить, а блокировать приём новых элементов?

            Я, конечно, не Эйнштейн, но метод Эйнштейна весьма полезен. Нужно иногда брать аксиому и превращать её в теорему. То есть пытаться понять, а аксиома ли то, что мы считаем аксиомой. Дак вот, рассуждения об очередях и стеке — это типичный пример того, как если порассуждать об аксиомах, окажется, что они вовсе и не аксиомы.


            1. mayorovp
              23.04.2019 08:33

              Потому что пиковая нагрузка обычно выше чем средняя.


            1. akryukov
              23.04.2019 09:51

              Уважаемый, вы путаетесь в показаниях.


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

              Вот за этим:


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

              С одним дополнением — вы не всегда можете так просто ограничивать очередь по емкости. У вас может быть требование от бизнеса "обработать все входящие запросы".


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

              Вы опять отвечаете на свой вопрос самостоятельно:


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

              Такие ситуации нужно отслеживать и предотвращать. Ждать когда мощностей даже с очередями не хватит — глупо. Нужно с самого начала собирать статистику нагрузки, экстраполировать тренд и масштабироваться с учетом будущей нагрузки. Если ресурсов внезапно не хватит, то это ЧП и отказ в обслуживании части клиентов.


              На первый вопрос ответ понятен: просто не умеем нормально проектировать.

              Если вы где-то встретили решение, которое использовало очереди не по назначению, то это проблема не "очереди", а решения.


              Про второй вариант ответ так же прост: мы просто сбросим содержимое очереди.

              Что вы будете делать, если у вас требование от бизнеса "обработать абсолютно все входящие сообщения"? "Просто сбросить" далеко не всегда так просто, как хотелось бы. Это вы видите запросы в очереди, а другие видят в них деньги и время.


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


  1. evocatus
    22.04.2019 12:13

    Зачем? Функциональный, типизированный, иммутабельный, но с возможностью обойти.
    Есть же F#, Clojure и Haskell (первый и третий при поддержке Microsoft)


    1. jbolshakov
      22.04.2019 15:01

      Согласен с вопросом. Язык похож на F#. Там так же можно сделать многое из статьи и mutable переменные есть.


  1. alloky
    22.04.2019 13:16

    Почему в новых мода описывать аргументы функций как имя: тип? Чем их не устраивает обычный стиль, тип имя?


    1. Cerberuser
      22.04.2019 13:25
      +1

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


      1. veslemay
        24.04.2019 13:55

        Ни от какого auto паскаль-стиль не уходит, а наоборот требует ввод кейворда для обозначения декларации переменной. Таким образом вы всегда будите писать синтаксический мусор вместо типа. Всякие там var, let и прочее.

        С типом будет ещё больше мусора, а именно let/var name: type, а не type name;


        1. math_coder
          24.04.2019 19:04

          Go опровергает ваши утверждения.


          1. veslemay
            24.04.2019 21:57

            Что именно он опровергает? Поподробнее. Вводом := или подобной фигни? Ну дак это не опровержение — это подтверждение, т.к. это и есть кейворд для отделения декларации от использования. К тому же, он к делу отношения не имеет, т.к. почти во всех языках используется var/let. И говорим мы о таком языке.


            1. creker
              24.04.2019 22:40

              Вот именно что опровергает. := позволяет опустить var и начать объявление с идентификатора переменной. Синтаксис полностью однозначен — либо сначала идет ключевое слово, либо идентификатор. Если мы ставим первым тип, то начинаются вечные проблемы с поиском этого типа и определением вообще, что это за хрень, чтобы потом уже определять, то ли это возвращаемое значение функции, то ли это переменная или еще какая хрень.


              1. veslemay
                24.04.2019 23:15

                Я уже объяснял — это не работает. Причин тому масса. Основная из них заключается в том, что как звучал тезис? «имя: тип что-то там позволяет». := — опровергает этот тезис, т.к. в данном случае абсолютно неважно где и как написан тип — одного «имя: тип»/«имя» недостаточно для определения переменной.

                К тому же, := — является таким же кейвордом, о котором я говорил. И абсолютно неважно в каком он будет виде. Т.е. мой тезис это никак не опровергает.

                К тому же, это вообще находится за рамками контекста т.к. контекстом является а) синтаксис принятый в обсуждаемом языке, б) синтаксис принятый в си.

                Так же, := — избыточен для ситуаций, где тип не выводится, а задаётся. Вам придётся либо использовать избыточность, либо вводить два типа операторов, что опять же — избыточность и синтаксический мусор.

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

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


                1. MacIn
                  24.04.2019 23:41

                  Основная из них заключается в том, что как звучал тезис? «имя: тип что-то там позволяет». := — опровергает этот тезис,

                  Если по сути, а не формально, то тезис звучал как «имя сначала, тип потом Vs тип сначала, имя потом». Далее спор шел о ключевом слове auto для авто-вывода против якобы необходимого var для обычного объявления. Двоеточие это только пример реализации первого подхода. Пример го показывает, как можно иметь имя сначала, не имея «синтаксического мусора» перед именем.

                  У вас простое взаимное недопонимание.


                  1. veslemay
                    25.04.2019 00:16

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

                    Нельзя. := — это синтаксический мусор, который, к тому же, писать сложнее нежели =, либо auto.

                    К тому же, как я уже говорил — мы либо вводим :=/=, либо мы имеем не только := в качестве синтаксического мусора, но и аннотацию при которой := избыточно.

                    Двоеточие это только пример реализации первого подхода.

                    Это так же неверно, т.к. двоеточие не имеет никакого отношения к подходу.

                    Я больше скажу — в си вообще аннотация типа ненужна. Она используется только для в одном случае — определение. Да и то нужен просто какой-то флаг для выражения намерения. Подойдёт вообще что угодно. const/auto/register. Всё это уже придумано и давно. Го просто взял эту логику из си.


                    1. creker
                      25.04.2019 01:06

                      Нельзя. := — это синтаксический мусор, который, к тому же, писать сложнее нежели =, либо auto.

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

                      Подойдёт вообще что угодно. const/auto/register

                      Это ли не тот синтаксический мусор. Вместо типа мы пишем вещи, которые вообще не имеют никакого отношения к делу. Модификаторы доступа и устаревшие ключевые слова, которые нынче ничего не значат.

                      Го просто взял эту логику из си.

                      В этом нет логики, это синтаксические извращения. В Го однозначный синтаксис, которые имеет четкие правила — либо :=, либо var. Все. Пример тут не с кого брать было.


                      1. veslemay
                        25.04.2019 01:26

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

                        Мусор. Вы как бот повторяете один и тот же набор шаблонных фраз.

                        Во-вторых, писать это несравнимо проще auto.

                        Основания этим заявлениям.

                        В-третьих, таки ничего лишнего перед именем переменной нет.

                        Есть после имени. До оно, либо после — это ничего не значит.

                        Это ли не тот синтаксический мусор.

                        Нет, вы действительно бот. Какое отношение эти рассуждения имеют к теме? Никакого. Абсолютно неважно что они значит — они значат тоже самое, что и :=, только ещё больше.

                        Вместо типа мы пишем вещи, которые вообще не имеют никакого отношения к делу.

                        Чушь какая. Они имеют отношения к делу и никто их вместо не пишет. Вам лишь сообщили, что подобная логика объявления без типа существовала и существует в си.

                        Модификаторы доступа и устаревшие ключевые слова, которые нынче ничего не значат.

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

                        В этом нет логики, это синтаксические извращения.

                        Опять же, когда нечего сказать — пиши херню.

                        В Го однозначный синтаксис, которые имеет четкие правила — либо :=, либо var. Все. Пример тут не с кого брать было.

                        Мне надоело с ботом разговаривать.

                        Хотите поиграть — хорошо, я жду эквивалента кода:

                        int a;

                        На го.


                        1. math_coder
                          25.04.2019 02:53

                          я жду эквивалента кода: int a;

                          Это не код, это говно (неинициализированная переменная).


                          А что касается того, что опровергает Go, то Go опровеграет два ваших утверждения: 1) необходимость мусора в виде двоеточия, отделяющего имя переменной от типа, 2) необходимость мусора в виде ключевого слова типа let, var или auto.


                          Двоеточие в := не является отдельным элементом/ключевым словом. Два символа := являются одним, единым оператором, поэтому никакого мусора при его использовании уже нет. (Не будете же вы настаивать, чтобы присвоение значения переменной выполнялось вообще без единого оператора?)


                          1. veslemay
                            25.04.2019 03:36

                            Это не код, это говно (неинициализированная переменная).

                            Т.е. ответа нет и адепт го порвался?

                            А что касается того, что опровергает Go, то Go опровеграет два ваших утверждения:

                            Фантазии брызжущих слюной адептов го.

                            1) необходимость мусора в виде двоеточия, отделяющего имя переменной от типа

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

                            Т.е. я могу использовать := в любом из стилей. Это просто сахар, костыль. Определяются переменные го не так.

                            2) необходимость мусора в виде ключевого слова типа let, var или auto.

                            Что за нелепая попытка врать. Читаем мой коммент:

                            Ни от какого auto паскаль-стиль не уходит, а наоборот требует ввод кейворда для обозначения декларации переменной. Таким образом вы всегда будите писать синтаксический мусор вместо типа. Всякие там var, let и прочее.

                            Т.е. брызжущий слюной адепт го врёт, утверждая, что говорил «необходимость мусора в виде ключевого слова типа let, var или auto.», но я приводил это лишь как пример.

                            Двоеточие в := не является отдельным элементом/ключевым словом.

                            Является.

                            Два символа := являются одним, единым оператором, поэтому никакого мусора при его использовании уже нет.

                            Два символа в if «являются одним, единым оператором». Опять методичка потекла.

                            Два символа := являются одним, единым оператором, поэтому никакого мусора при его использовании уже нет.

                            Он и есть мусор, т.к. есть уже оператор =. А это другой оператор, который является костылём для решения избыточности паскаль-стиля.

                            (Не будете же вы настаивать, чтобы присвоение значения переменной выполнялось вообще без единого оператора?)

                            Опять чушь. Именно те, кто рассказывал про «проблему auto» утверждали, что переменную можно объявлять без избыточности.

                            Я же сообщил, что это неверно и нужен механизм отделения. В ситуации же си-синтаксиса механизм ненужен — он уже есть.

                            В ситуации же с паскаль-синтаксисом он нужен. Это var/let и прочая фигня. Именно с var сделан ваш го. А далее закостылено := — которая является таким же механизмом, лишней сущностью она повторяет уже существующие функционал.

                            Вообщем, вы, насколько я погляжу, особо вменяемостью не блещете. Спорить о чём-то с ботами бесполезно, поэтому я вернуть к сити, а именно.

                            Я отвечал изначально в контексте преимущества паскаль-стиля, т.е. я это опровергал. Теперь вам нужно сообщить — каким образом := относится к паскаль-стилю? Я заранее отвечу — никаким. Новы там можете попытаться что-то придумать.


                      1. veslemay
                        25.04.2019 01:32

                        Я даже не поверить, что я отвечаю на настолько нелепые рассуждения.

                        Есть синтаксис var name type =, базовый. Данный пациент утверждает, что никакой избыточности нет. Но авторы го с ним несогласны.

                        Именно поэтому вводится var (), это есть ещё со времён паскаля. Потому что все очевидно, что объявление с аннотацией через var — это избыточно. Т.е. пациент спорит с объективной реальностью.

                        Аналогично с := — это синтаксический сахар, который был добавлен специально для решения проблемы var name auto =.

                        Т.е. мы имеем как минимум два варианта объявления переменных, но что же там нам сообщал пациент:

                        В Go объявление функции, объявления типа указателя на функцию, передача функции как объекта первого порядка — все это идентичные синтаксически вещи

                        Он заявлял, что проблема С++ в том, что синтаксис разный. В целом эти базовая методичка го «делаем что-то одним способом», но.

                        Как мы видим, что тут эта методичка ломается. Потому что способов как минимум 2(3). А почему? Потому что общий случай избыточен и добавлен специальный сахар для решения проблемы.


    1. evocatus
      22.04.2019 13:50

      Обычный это как в Algol 60?


    1. akryukov
      22.04.2019 13:50

      Активно пишу на scala, где аргументы описываются как имя: тип.
      На мой взгляд, такой стиль побуждает думать сначала о смысле переменной, а потом уже выбирать подходящий тип.
      Допустим пишу функцию "calculate". Например для вычисления баланса по множеству операций. Сначала есть код:
      function calculate(
      Эта функция принимает в себя множество операций. Добавляю
      function calculate(operations:
      Какую лучше коллекцию сюда передавать? Сортированный список или set. Продумываю оба варианта и выбираю список. Тогда добавляю в код
      function calculate(operations:SortedArray){


      Мелочь, но позволяет думать в первую очередь о бизнес-логике, а потом уже о инструментах для ее реализации.


      1. veslemay
        24.04.2019 14:04

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

        Тип и определяет смысл.

        множество

        Тут ваша логика дала течь. Множество уже тип, вы подумали о типе до.

        Опять же, существует два варианта — от данных, либо от операций. От данных — это когда у вас уже есть логика, которая генерирует данные и типы их уже выбраны. Тогда вы в первую очередь должны писать тип.

        От операции. Ты вы пытаетесь реализовать какую-то операцию и в процесса выводите тип. Очевидно, что этот процесс находится в теле функции и с какой он находится — неважно. Абсолютно.


    1. Flammar
      22.04.2019 14:15

      Чтобы иметь конструкцию [имя][[: тип][ = значение]].


    1. vitvakatu
      22.04.2019 14:30
      +1

      Странно использовать слово "обычный" в этом контексте. Парсерт непротиворечимой грамматики написать легче в этом случае, только и всего.


    1. surly
      23.04.2019 13:02

      Ага, а потом начинается «прелесть»: *(** тип[ ]) имя()[ ]


      1. veslemay
        24.04.2019 14:19
        +1

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

        В си-стиле выражается void(a, b, c); В паскаль стиле нет. В том же TS приходится эмулировать сишный стиль через (a, b, c) => void, т.е. семантика потекла. Нужно два синтаксис для определения типа и функции.

        И таких примеров масса. К тому же не стоит сравнивать скриптуху, где одни ссылочные типы и си. Это разные весовые категории. Это как сравнивать С++-лямбду и js-лямбду.

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


    1. nmrulin
      23.04.2019 17:53
      -1

      Так как раз имя: тип очень логичный стиль применяется ещё в Паскале. А С++ стиль тип имя замедляет чтение кода. Обосенно плохо когда описывается сложный тип например
      struct building //Создаем структуру!
      { char *owner; //здесь будет храниться имя владельца
      char *city;

      Мы сначала говорим, что это структура, потом даём имя типа, а потом уточняет.
      А логично делать наоборот
      building =record и дальше уточнение.
      Вообще с порядком в С++ но очень.
      Например логично закодировать. Указатель на хрю-хрю как ^hru_hru. Или Хрю-хрю указывает на — hru_hru^. А если сделать обратный порядок, получиться чтение справо налево.


      1. veslemay
        24.04.2019 14:31

        А логично делать наоборот

        Почему? К тому же везде и всюду сделано аналогично и здесь:

        function update
        entity Foo {

        И так далее.

        Например логично закодировать. Указатель на хрю-хрю как ^hru_hru. Или Хрю-хрю указывает на — hru_hru^. А если сделать обратный порядок, получиться чтение справо налево.

        Распарсить это решительно невозможно. Это какой-то набор слов. Напишите что-то более адекватное типа «в крестах так: бла-бла, а нужно так: бла-бла».


        1. Bronx
          24.04.2019 19:30

          К тому же везде и всюду сделано аналогично и здесь:
          function update
          entity Foo

          Это как раз ближе к var foo, потому что слева от имени стоит не тип, а ключевое слово, категория имени (функция, структура или переменная), а тип как раз стоит справа: параметры и возвращаемое значение для функции, список членов для структуры и имя типа для переменной:


          category  | name   | domain                  | codomain
          -----------------------------------------------------------
          function    update   (id: int, data: string) : bool
          entity      Foo      {id: int, data: string}
          var         foo                              : Foo


          1. veslemay
            24.04.2019 22:18

            Это как раз ближе к var foo

            Это какие-то попытки подменить изначальный тезис. Был пример со sturct — я показал, что в этом языке используется такая же форма определения объектов. Она используется везде, в том же тайпскрипте.

            потому что слева от имени стоит не тип

            Где тут: struct name — стоит слева тип? Нигде.

            Начнём с того, что сишный sturct под неё подходит, а говорилось именно о нём. Так же никакое положение в таблице не обосновывается, никак. Т.е. на каком основании "(id: int, data: string)" является «domain», а bool не является. К тому же, ваша табличка игнорирует override method, ref env.

            Ну и на самый главный вопрос нет ответа. Почему? Можно нарисовать какую угодно табличку, но вопрос заключается в том — почему так должно быть? Зачем строить свои рассуждения на догматах?


            1. Bronx
              25.04.2019 04:21

              Ок, прошу прощения, проглядел пример building = record от nmrulin и почему-то решил, что вы всё ещё про запись "тип имя", так что действительно вышло не в тему.


              на каком основании "(id: int, data: string)" является «domain», а bool не является

              (id, data) — это "вход" функции, область определений (domain), а bool — выход, область значений (codomain). Запись f(int, string) => bool или f(int, string): bool вполне математична: "f есть отображение множества кортежей типа (int, string) на значение во множестве bool".


              А как прочесть запись bool f(int, string) в парадигме "тип имя"? "Функция типа bool с именем f"? Но беда: тип этой функции не bool, а вовсе даже bool (int, string).


              1. veslemay
                25.04.2019 05:50

                А как прочесть запись bool f(int, string) в парадигме «тип имя»? «Функция типа bool с именем f»? Но беда: тип этой функции не bool, а вовсе даже bool (int, string).

                У вас дара в логике.: — семантически отделяет тип. Вы игнорируете сей факт и свободно подменяете семантику: во имя подбития реальности под свою модель.

                К тому же, вы взяли какую-то логику и каким-то образом определили её за правильную, а далее исходите из того, что всё что иное — неправильное. Ведь любая другая логика — неправильная.

                С таким же успехом можно сказать про ref и про override и прочее. Вы говорите о каком-то примитивном обрубке, а не о каких-то общих правилах.

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

                Начнём с того, что сишный синтаксис создан как f(a, b) {} — изначально все типы были auto(из крестов). Правда там не было вывода типов, а универсальный тип просто был интом.

                Всё что слева/справа ничего не значит. При этом в си есть прямое разделение на право и лево. Есть тип, а есть объект. То, что написано справа — относится к объекту, а всё что слева — к его типу.

                В примитивных языка такого разделения нет — на то они и примитивные. В том же bosque разделение уже появляется — там есть тот же ref, т.е. то, что относится к самому объекту.

                Можно, конечно, делать это делать слева до :, как многие и делают. Но, очевидно, что получается полный треш. Всякие там name?: type.

                Правда в Си всё не совсем так. Там тип не может быть массивом, потому что массив — это объект. Так же как типом не может быть функция.

                Хотя, конечно, в си есть и тип-функция и тип-массив, но только в рамках тайпдефа. Так же, есть (int[]){} — это логика исходит из того же. По такому же принципу работает using в С++.

                Если проще. Объект может переменной — это просто тип. Если мы видим просто тип — это тип какого-то объекта/переменной.

                Но, в случае с [] — типом будет массив. Объект будет массивом. А типом указывается тип возврата операции/тора [], аналогично и с () — скобочки уже из объекта делают функцию. А всё остальное к делу отношения не имеет. Тип, который слева — это не тип объекта — это тип возвращаемый (). Потому что свободный тип — это всегда объект(какого-либо значение).

                Поэтому си читается следующим образом. void f(); f — это идентификатор/имя. Вы без проблем можете писать void f()[] — функция будет возвращать массив. Тоже самое с [][], вы можете написать int arr[10]() — тоже без проблем.

                И это бы всё работало круто, но в си есть фундаментальное разделение. Есть объекты как значения(которые могут быть значениями), а есть которые не могут. Вот [] и () значениями быть не могут.

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

                Описать его можно так. Есть база, которой вы даёте тип. Тип задаётся как справа так и слева. Причём есть два типа типов. Тип самого объекта(массив/переменная(значение)/функция), который пишется справа. И всякие расширения — это слева.

                f() — это функция, тип объекта. Слева накидываются всякие свойства, свйоства накидываются ИМЕННО на объект(это упомянутая мною база). f тут уже вообще не при делах.

                () — расширяется параметрами. Так же, он возвращает какой-то объект. Тип объекта справа не написан — значит это обычный объект/значение. Этот объект является базой. Ему можно задать тип и всякие там квалификаторы.

                * — это тип. Никаких «на» там нет. Это просто упрощение. * — такая же база. Правила те же, но она слева и приоритет у неё меньше. Именно для этого там скобочки — они выделяют новую базу.

                И теперь, я думаю, вы сами сможете прочитать bool f(int, string)

                База по умолчанию — идентификатор. Идентификатор имеет тип-объект функция. f — это функция, () — имеет семантику «аргументы и „возвращаемое для операции () значение“(по-колхозному возвращает значение)». Читаем аргументы. Аргументы типа инт и строка. Далее эта функция что делает? Возвращает значение(справа ничего нет). Далее, слева могут стоять уточняющие, а именно тип значения и его квалификаторы.

                Так же там могут стоять «квалификаторы», которые воздействуют на сам базовый объект.

                f — функция с аргументами инт и строка, возвращающая(по-колхозному) значения типа bool.


                1. Bronx
                  25.04.2019 09:54

                  У вас дыра в логике: — семантически отделяет тип

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


                  • справа от имени — всё, что про тип, т.е. про область всех возможных значений. Для скаляров — просто имя уже имеющегося типа (встроенного или определённого). Для агрегатов — перечисление типов членов агрегата. Для функций (которые есть мост между двумя областями, входом и выходом) — как типы аргументов, так и тип возращаемого значения.
                  • слева от имени — то, что про сам объёкт. Например категория (var/const/enum/function/struct/class), видимость объекта (public/private), модель хранения (static/const/readonly), модель передачи параметра (in/out/ref), модель вызова метода (virtual/static) и прочee. Всё это не является частью типа.

                  В результате первого правила функции получают настоящий тип, а не несовместимый "тип-объект с расширениями", становятся гражданами первого сорта, могут быть присвоены переменной, проверяются при присваивании как по параметрам, так и по возвращаемому значению, иначе будет ошибка типа.
                  И, заодно, массивы теперь получают полноценный тип, как и любой другой агрегат или строка (массив символов), а не "тип-объект", чей тип при передаче в функцию внезапно протухает и разлагается до указателя.


                  Но, очевидно, что получается полный треш. Всякие там name?: type.

                  Но очевидно, что name?: type — это просто сахар для каноничной записи name: type | undefined, который слишком часто встречается и слишком длинно писать каждый раз. Правило 1 выполняется: ?:type находится справа от name.


                  всякие расширения — это слева.…
                  () — расширяется параметрами.

                  Параметрами тоже слева? Упс, строгая логика поломалась — параметрами расширяем таки справа, т.е. внутри (). И теперь у нас расширения то слева, то справа.


                  Вы без проблем можете писать void f()[] — функция будет возвращать массив.

                  Вы уверены? Я плюсовик, не голый сишник, но насколько мне известно, ANSI C не позволяет функциям возвращать массив, только указатель, и объявление будет примерно таким монстриком: void (*f())[N]. В высшей степени интуитивная конструкция.


                  Претензию про ref и override так и не понял: что конкретно вам не нравится, и как именно они ломают логику?


                  1. veslemay
                    25.04.2019 10:54
                    -1

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

                    С чего вдруг она меняется? Основание.

                    Полный тип может включать в себя больше чем то, что после двоеточия, но правило то же:

                    Т.е. двоеточие не имеет никакого отношения к типу. Из этого прямо следует, что тип не только справа от двоеточия, либо только. Третьего не дано. Либо двоеточие ничего не значит.

                    Что самое интересное — эти манёвры следствие попытки оправдать неоднозначность, которой там, на самом деле, нет. Т.к.: там там же отделяет тип. И типом является именно возврат, ведь тип возврата и определяется. Аналогично работает и для ?:type. Когда? является признаком опциональности и точно так же относится к имени, а не определяет ?:type — новый синтаксис для типа. Потому что тогда нужно было ?type, либо type?..

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

                    Вам не нужно мне перечислять те случаи, где его семантика потекла — я и так это знаю. Нужно отвечать на вопрос а) зачем оно нужно. б) почему у него изменяется семантика.

                    слева от имени — то, что про сам объёкт. Например категория (var/const/enum/function/struct/class), видимость объекта (public/private), модель хранения (static/const/readonly), модель передачи параметра (in/out/ref), модель вызова метода (virtual/static) и прочee. Всё это не является частью типа.

                    Всё это хорошо, но без интеграции в предыдущие рассуждения — это просто перечисление не относящиеся к теме. Интегрируйте его в изначальную вашу модель. public — это категория? Что это?

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

                    В результате первого правила функции получают настоящий тип

                    Какие критерии для «настоящий»? Почему меня должен волновать какой-то фентезийный «настоящий тип».
                    а не несовместимый «тип-объект с расширениями»

                    У вас опять рассуждения потекли. Вы там забыли про ref/const и прочее. Это такие же «расширители» и без ник никакая аннотация типа не определяет объект, а является лишь частью определения.

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

                    Ну во-первых это наивные манипуляции, когда сравнивается несравнимое. Т.е. берётся скриптуха и её примитивная модель и сравнивается с более сложной моделью, при этом примитивность и её следствия превращаются в следствия синтаксиса/«настоящих типов».

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

                    Опять же. Сравнение примитивной скриптухи и более сложной модели.

                    Но очевидно, что name?: type — это просто сахар для каноничной записи name: type | undefined, который слишком часто встречается и слишком длинно писать каждый раз. Правило 1 выполняется: ?:type находится справа от name.

                    Я не понимаю две вещи. На каком основании вы дёргаете куски фраз и отвечаете только на удобное. Зачем вы мне повторяете то, что я уже до вас вам сообщил?

                    Можно, конечно, делать это делать слева до :, как многие и делают. Но, очевидно, что получается полный треш. Всякие там name?: type.

                    Здесь именно говорится о том, что ?: — справа от name. И именно поэтому этот пример называется трешем.

                    При этом это я говорил про этот: [Int, ?:Bool], никакого name тут нет. А вот лево есть. Тут, конечно, можно пытаться задним числом опять изменять семантику для :, но очевидно — что это эквивалент name?:type и значит это не type|undefined, а именно опциональный аргумент. Мне лень читать и искать это в мануале, но любо это дыра в логике языка, либо действительно так.

                    Параметрами тоже слева?

                    С чего вдруг? Опять нелепая попытка дёргать фразы. Расширения — это квалификаторы, в разных контекста это понятия значит разное.

                    Упс, строгая логика поломалась

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

                    С чего вдруг она справа, если они внутри? Отсчёт идут от () — очевидно, что внутри никаким образом не может быть ни справа ни слева.

                    Вы уверены? Я плюсовик, не голый сишник, но насколько мне известно, ANSI C не позволяет функциям возвращать массив,

                    Я уверен. К тому же у вас опять какие-то проблемы с восприятием. Мы говорим о синтаксисе, а не о том, что си позволяет/не позволяет делать. Синтаксис это позволяет.
                    только указатель, и объявление будет примерно таким монстриком

                    Основания в студию.

                    : void (*f())[N]. В высшей степени интуитивная конструкция.

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

                    Конечно, куда там этим конструкциями до *[N]void f(); — вот оно, чудо человеческой мысли.

                    Или это: []int{1000, 2000, 12334} как перепаста с сишного (int[]){1000, 2000, 12334}. struct{f int}{50} — вот оно, удобство.

                    Претензию про ref и override так и не понял: что конкретно вам не нравится, и как именно они ломают логику?

                    Я уже обозначил выше проблему — как это интегрируется в вашу табличку.


        1. nmrulin
          24.04.2019 21:40

          Ну так вы справо налево читаете все предложения видимо, а теперь прочитайте как все обычные люди слева направо. И расшифруйте выражение "^hru_hru" — так, чтобы каждому обозначению соответствовало слово. А теперь попробуйте сделать это c выражением hru_hru*. У вас это не получиться.

          В этом то вся и проблема. Некоторые последователи С++ именно, что могут только «парсить» текст. А забыли, что 99% текст не парсят, а читают. Так вот напоминаю вам что чтением в отличие от «парсения» является процесс восприятия информации слева направо. Поэтому можно написать только лишь предложение «Указатель на переменную хрю-хрю». И это будет для всех текст, только для вас набор слов. И наоброт, предложение «Хрю-хрю на укаказатель переменную » -будет для вас текстом, а для 99% людей набором слов.


          1. veslemay
            24.04.2019 23:06

            И расшифруйте выражение "^hru_hru" — так, чтобы каждому обозначению соответствовало слово.

            Дак вы должны это сделать — как я буду читать непонятно какие, придуманные вами, символы?

            а теперь прочитайте как все обычные люди слева направо

            Как нам разница — как и кто читает? К тому же нужно отличать чтение от понимания. Читать можно как угодно. К тому же, прочитайте мне 123.123. Прочитай мне a + b * (c + d).

            Я могу читать как угодно, как и любой другой человек. И все именно так и читают. Читают таблицы сверху вниз, либо таблицы нужно запретить? Ищут ключевые слова в текста. Запоминают контекст.

            А теперь попробуйте сделать это c выражением hru_hru*. У вас это не получиться.

            Указатель — это тип *, T — это тип возврата операции разыменования. Слева всегда стоит конечный тип. Сишные определения читаются как математические выражения. Вот паста, где я разбирал «как читать».

            Паста
            // Нужно понять фундаментальную вещь - есть база, это некий контекст который расширяют расширятели типов.
            
            //по дефолту база - это то, что справа. Базой любого типа является определение(имя).
            
            
            typedef int f_t();//функция. База - имя. () - расширяет имя, делая его функцией. Функция теперь является базой. 
            // Для этой коснтрукции с лева пишется тип возврата:
            
            f; //имя 
            
            f0();//функция.
            int f1();//функция с типом возврата.
            
            * f2();//функция с типов возврата "указатель".
            
            int * f3();//для int базой является * - определение типа операции *(разименования) у указателя.
            
            typedef int f0_t();//правила аналогичны. Функция. 
            //хотим сделать указатель на функцию
            typedef int * fptr_t();//базой является функция - определяется тип возврата. Указатель.
            //нужно как-то определить базу для *, чтобы она была именем. Ведь имя должно быть не функцией(как сейчас), а указателем.
            
            typedef int (* fptr0_t)();//база для * имя. Далее скобки выступают базой. 
            //определяется тип операции * у указателя. Указатель является базой.
            
            typedef int (** fptr1_t)();//мы определил тип операции * для указателя(который слева от fptr1_t).
            // Базой является тип операции * для указателя, которая является типом операции * для указателя, который является типом для fptr1_t
            
            typedef int (** fptr2_t[])();//fptr2_t теперь является массивом. Массив - база. Слева у массива определяется тип элемента массива.
            
            
            typedef int (** fptr3_t[][7])();//здесь можно просто упростить до "fptr3_t - двойной массив". Двойной массив - база. Свйоства аналогичным одинарному.
            
            typedef int * (** fptr4_t[][7])();//базой является функция. Для неё определяется тип возврата. Мы определили тип возврата - указатель. Далее мы уже знаем. int тип операции * для указателя.
            
            typedef int * (** fptr5_t[][7])()[];//базой является функция. Типом определён указатель. Это не то, что мы хотели.
            
            //мы хотели определить тип не для функции, а для типа операции * у указателя. Нам нужно сделать базой указатель.
            
            typedef int (*(** fptr6_t[][7])())[];//база указатель. Типом для базы определяется массив. Массив база - для базы(массива) определяется тип элемента - int
            
            
            typedef int * (*(** fptr7_t[][7])())[];//база массив. Для массива определяется тип элемента - указатль. Для указателя определяется тип операции *.
            
            
            //тут можно вывести два правила. Право имеет приоритет. Для лева - базой является то, что справа. Для права - лево.
            
            int a[1];//имя - база. Справа - массив. База массив. Для него определён тип - инт, как тип элемента массива.
            
            int ((a)[1]);//можно руками определить базы, как это делается по-дефолту.
            
            int * b[1];//b - база. Для неё определён массив. Для массива определён тип(элемента) - указатель. Для указателя определён тип операции* - int.
            int (*c)[1];//c  - база(имя). Для неё опредён тип - указатель. Для указателя определён тип операции* - массив. Для массива определён тип элемента - int.



    1. Bronx
      24.04.2019 01:01

      Потому что если мы принимает порядок "тип имя" для аргументов функций, то для единообразия придётся применять этот порядок везде: при объявлении переменных, членов структур, возвращаемого типа у функции и т.п. И получаются приколы с неоднозначностью типа most vexing parse. Ну вот, например:


      Foo foo();


      — это объявление и инициализация переменной foo типа Foo, или объявление функции foo() без параметров, возвращающей значение типа Foo?


      1. veslemay
        24.04.2019 14:26

        то для единообразия

        Паскаль-стиль не может быть единобразным — он слишком слабый даже для языков уровня js.

        И получаются приколы с неоднозначностью типа most vexing parse.

        И в чём проблема?

        Расскажите мне про прикол с:

        (a, b) => c — что это?
        А про [a, b, c]?

        К тому же, очень наивно ссылаться на проблему, которая вообще не проблема и которую уже решили. И об этом написано по ссылке.


    1. creker
      24.04.2019 22:37

      Тем, что таким образом упрощается парсинг языка и исключаются неоднозначные ситуации, которых в С/С++ предостаточно. Первым всегда идет или ключевое слово или идентификатор. Тоже самое с переносом возвращаемого значения функции в конец и использованием ключевого слова вроде func — упрощает парсинг и делает адекватным использование функций первого порядка. В отличие от упомянутых С/С++, где это пытка сплошная.


      1. veslemay
        24.04.2019 23:19

        Тем, что таким образом упрощается парсинг языка и исключаются неоднозначные ситуации

        Кому, кроме студентов, интересна сложность парсинга? Язык должен быть мощным и удобным, а насколько его сложно парсить — никому не интересно.

        исключаются неоднозначные ситуации

        Пустой лозунг, который я уже опровергал выше.

        Первым всегда идет или ключевое слово или идентификатор.

        Опять лозунг. Хорошо оно идёт — дальше что?

        упрощает парсинг и делает адекватным использование функций первого порядка.

        Парсинг никому не интересен. Чем это использование более адекватно? Что вообще это значит. Опять какой-то лозунг без примеров/объяснений.

        В отличие от упомянутых С/С++, где это пытка сплошная.

        Опять же, в чём заключается пытка?


        1. creker
          25.04.2019 00:52

          Кому, кроме студентов, интересна сложность парсинга? Язык должен быть мощным и удобным, а насколько его сложно парсить — никому не интересно.

          Всем, кто потом будет работать с инструментами, которые язык парсят и что-то делают с AST. Таких для Go множество и именно благодаря его однозначному и простому синтаксису. Это ускоряет и сам процесс парсинга, что полезно вообще всем.

          Пустой лозунг, который я уже опровергал выше.

          Никакого опровержения не заметил. Отсутствие неоднозначности в синтаксисе языке несет за собой далеко идущие преимущества. И Go этому яркий пример.

          Опять лозунг. Хорошо оно идёт — дальше что?

          То, что парсить легко. Дальше логику сами можете достроить.

          Опять же, в чём заключается пытка?

          В том, что в С/С++ синтаксис указателя на функцию ужасен, нечитабелен, сложен для написания и полностью отличается от того, как функции объявляются. Чего стоит только необходимость включения имени переменной в сам тип вроде int(*foo)(). В Go объявление функции, объявления типа указателя на функцию, передача функции как объекта первого порядка — все это идентичные синтаксически вещи, что значительно упрощает чтение и написание кода. Авторы Go к этому стремились, делая такой синтаксис, и они своего добились. Помимо этого, С++, будучи заложником своей извращенной грамматики, придумал тот ужас, которым называют лямбды в этом языке. Тоже самое в C# том же, хоть и не настолько ужасно.

          Вы уперлись в какие-то ваши странные представления о том, какой должен быть язык, не понимая, что С/С++ и им подобные это одни из худших примеров с точки зрения синтаксиса. Поэтому не случайно языки нынче выбирают совершенно иную логику, в том числе «идентификатор: тип», func/fun перед функцией и прочее и прочее. Люди наелись проблем этих языков и не хотят тащить теже самые проблем себе, только потому что все привыкли и вроде как все в порядке уже.


          1. veslemay
            25.04.2019 01:18
            -1

            Всем, кто потом будет работать с инструментами, которые язык парсят и что-то делают с AST. Таких для Go множество и именно благодаря его однозначному и простому синтаксису. Это ускоряет и сам процесс парсинга, что полезно вообще всем.

            Попросту враньё. Инструментов по статическому анализу С++-кода больше и они куда как мощнее и качественнее, чем для го. Никакой С++ парсить ненужно.

            К тому же, это враньё ещё и тем, что в го нужны парсеры потому, что язык крайне примитивен и ничего не может. От того и нужнается в кодогене и тысячах костылях, для обхода отсутствия тех же генериков.

            Никакого опровержения не заметил. Отсутствие неоднозначности в синтаксисе языке несет за собой далеко идущие преимущества. И Go этому яркий пример.

            Т.е. у вас ничего, кроме лозунгов, нет? Где преимущества, в чём преимущества? Го в сравнении с тем же жаваскриптом/тайпскриптом — пыль. Я уж не говорю про С/С++. Что мне показывает пример го? Да ничего.

            То, что парсить легко. Дальше логику сами можете достроить.

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

            В том, что в С/С++ синтаксис указателя на функцию ужасен

            Примеры. Зачем мне лозунги? Конкретно. Берёте идентичный код и пишите его на го и на С++.

            нечитабелен

            Опять лозунги?

            сложен для написания и полностью отличается от того, как функции объявляются.

            Вы ведь ничего не знаете. Функция объявляется так же.

            Чего стоит только необходимость включения имени переменной в сам тип вроде int(*foo)().

            У вас явно лозунги плывут. Функции в си записывается как int(foo)(); Указатель записывается как int(* foo)(); То, что вы этого не знаете — это проблему. Узнайте/спросите перед тем, как делать далеко идущие заявления.

            В Go объявление функции, объявления типа указателя на функцию, передача функции как объекта первого порядка — все это идентичные синтаксически вещи, что значительно упрощает чтение и написание кода.

            Опять лозунги. Приведите пример.

            Авторы Go к этому стремились, делая такой синтаксис, и они своего добились.

            Это настолько нелепые заявления. Синтаксис го не может и 10% того, что может синтаксис си в С++, в том же C#. Зачем сравнивать несравнимое?

            Это примерно как рассказывать, что у мышки 3 кнопки, а у клавиатуры 100. Вот ведь какая клавиатура плохая — кнопок много. Авторы мышки стремились сделать такое кол-во кнопок(малое) и они добились этого.

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

            Помимо этого, С++, будучи заложником своей извращенной грамматики, придумал тот ужас, которым называют лямбды в этом языке. Тоже самое в C# том же, хоть и не настолько ужасно.

            Она извращённая лишь потому, что вы где-то это услышали? Сильная аргументация.

            И да, у вас опять лозунг потёк. Покажите мне эквивалент С++-лямбды на го, либо на другом языке.


          1. IvanNochnoy
            25.04.2019 07:47

            Всем, кто потом будет работать с инструментами, которые язык парсят и что-то делают с AST. Таких для Go множество и именно благодаря его однозначному и простому синтаксису. Это ускоряет и сам процесс парсинга, что полезно вообще всем.

            Есть другой подход: compiler as a service, как это сделано в C#/TypeScript. В этом случае необходимость писать собственные парсеры отпадает, равно как и намеренно упрощать синтаксис.


            1. veslemay
              25.04.2019 07:59
              -1

              Есть другой подход: compiler as a service, как это сделано в C#/TypeScript.

              Именно этим и занимается clang уже 10лет. Да и уже лет 20 есть gcc-xml, которого для базовых вещей вполне хватит. Причём лучше, чем упомянутые выше случаи.

              Тут двойной факап. И упоминания С++, который находится в авангарде «compiler as a service» и догматическая уверенность в одном избранном случае.


  1. dimAdmin
    22.04.2019 14:39
    +1

    Главная миссия дизайна языка —… чтобы он был прост и понятен как для человека, так и для компьютера.

    Паскаль же вроде давно придумали, зачем снова разводить «зоопарк»???


  1. NotThatEasy
    22.04.2019 15:07

    Вообще, симпатичный синтаксис, однако, рекурсия тут задумана как некий «Unsafe» элемент… Стоп, что? Язык, претендующий на функциональность со всеми этими иммутабельностью, пайплайнами, вызовами фильтер/мап/редьюсов в ДжаваВосемь-стиле, только через стрелочки, и этот язык предлагает огромную кодобазу отмечать как рекурсивную, хотя мне не припоминается, чтоб у компиляторов когда-либо были проблемы с распознаванием рекурсивных вызовов в коде, с тех пор как в них добавляли поддержку рекурсивных вызовов.
    Крайне занятная задумка со стринг-типами, хотя слишком сыро и конкретно – надо расширить на систему типов по возможности (я вижу отличное применение такому функционалу – он вполне может потеснить костыльнуть Хаскелльные тайпклассы, пусть и работает в другую сторону, так же, как и концепты из С++20).
    Также интересно отсутствие UB, но это не гарантирует, что программа будет себя вести, как задумано. Более того, никто ещё не видел ошибки реальных программ, а это очень важно – всегда придерживался и придерживаюсь мнения, что максимум ошибок надо ловить в компайлтайме.

    Общее впечатление: симпатичный синтаксис (а больше пока ничего и нет), вангую проприетарный майкрософтовский F# x переRust.


    1. NotThatEasy
      22.04.2019 16:06
      -1

      P.S.: Насчёт ссылочности и сохранения иммутабельности, как по мне, всё просто: пример кода в статье на эту тему – негодный и не должен ни компилиться, ни, тем более, запускаться. В сигнатуре функции надо обязать указывать mutable var для изменяемых переменных. При правильно прикрученной системе вывода типов получим синтаксис функции вроде:

      function foo(var ref bar/*Тип указан только для второй переменной, в то время, как тип первой выводится*/, ref strategy: Int) /*Тип возвращаемого значения выводится сам*/
      {
      bar += 1;
      //Ошибочный код:
      //strategy += 1;
      return bar;
      }

      Что в принципе миленько – возможность контроля типов получаемых и возвращаемых значений функции, как и их модификаторов.


      1. mayorovp
        22.04.2019 16:28

        А в чём смысл дублирования слова ref словом var? И почему нельзя написать просто strategy: Int, без ref?


        1. NotThatEasy
          22.04.2019 16:43

          ref – Указание, что принимаемый тип будет ссылочным, а var же указывает на мутабельность.
          Я провожу аналогию в меру своих знаний, а именно:

          На плюсах можно написать:
          /*void foo*/
          (int a)
          (int& a)
          (const int& a)
          Что будет значить три разных вещи. 1 – int скопируется новой переменной. 2 – будет передан мутабельный параметр по ссылке. 3 – передастся ссылка на константную (то есть, неизменяемая, она же мутабельная) переменную (константную ссылку на переменную, но не суть).

          Имеем:
          ref strategy: Int –> const int& strategy
          strategy: Int –> const int strategy
          var ref bar –> template T& bar
          ref bar –> template const T& bar

          Почему я использую ref для strategy – привычка, больше скажу, я консты не всегда пишу, и потому всеми конечностями за иммутабельность по умолчанию


          1. mayorovp
            22.04.2019 16:52

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

            В том же C++ константные ссылки используются, как правило, для оптимизации; но в современном языке такую оптимизацию лучше поручить компилятору.

            Таким образом, константные ссылки — не нужны, и остаётся всего два типа передачи параметра: по значению и по изменяемой ссылке. Именно второй способ и достигается при помощи слова ref.


            1. Static_electro
              22.04.2019 17:34

              Мне кажется, вы здесь излишне упрощаете, потому что в С++ константные ссылки используются еще и как гарантия той самой иммутабельности при отсутствии сайд-эффектов от копирования.
              Т.е. если у меня на руках «тяжелый» константный объект, который хочется отдать как параметр в функцию, то константные ссылки — это хорошая вещь.


              1. creker
                22.04.2019 18:27

                Они работают только в одну сторону — чтобы получатель не изменил что-то по ссылке. А вот получателю нет никаких гарантий, что объект «иммутабельный» внезапно из стула не превратится в верблюда, потому что кто-то снаружи что-то внутри него дернул. По сути, это делает бесполезной всю эту затею, почему давно const модификатор скорее плохим тоном и мусором считается, которые постоянно мешает, чем реально полезным инструментом.


                1. Static_electro
                  22.04.2019 18:34
                  +1

                  Хм. Интересно, можно сыылки на «плохой тон и мусор»? Я на полном серьезе, любопытно посмотреть.


                  1. creker
                    22.04.2019 18:45
                    -1

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


                    1. NotThatEasy
                      22.04.2019 19:09
                      +1

                      Ни разу не встречал обсуждение «проблемы const», Вами так с лёгкостью окрещённой, однако, могу представить Вам пример полноценной иммутабельности на С++:

                      int main(void)
                      {
                      const int i = 0;
                      ++i;
                      //Всё как мы и ожидали, ошибка компиляции «expression must be a modifiable value»
                      }

                      Const – имхо не самая сложная тема при изучении С-подобных языков.


                      1. creker
                        22.04.2019 19:39

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


                      1. mayorovp
                        22.04.2019 23:52
                        -1

                        Так с точки зрения вызывающего кода с const и правда никаких проблем, проблемы начинаются у вызываемого кода, получившего константную ссылку…


                    1. Static_electro
                      22.04.2019 19:11
                      +1

                      Из очевидных проблем могу назвать const_cast & mutable. Но что есть — то есть, вот с таким сиплюплюсом мы живем. Имхо, это не делает написание конст-корректного кода бесполезным занятием. А встретив на код-ревью эти попытки обмануть конст, можно смело начинать спрашивать о причинах.


                1. NotThatEasy
                  22.04.2019 19:01

                  Если во внешнем скоупе объект иммутабельный, то такой проблемы и не будет (бишь, функциональный подход для меня по большей части в этом и заключается), а с неизменяемостью по умолчанию – не придётся вообще писать mutable var.


                  1. creker
                    22.04.2019 19:08
                    -1

                    Ну т.е. это совсем не const решается и не может решаться. Это либо весь язык таким должен быть, либо интерфейс у объектов такой, что они иммутабельны по-умолчанию. А так получается ни туда, ни сюда.


                    1. NotThatEasy
                      22.04.2019 19:24

                      объект «иммутабельный» внезапно из стула не превратится в верблюда, потому что кто-то снаружи что-то внутри него дернул

                      Вы апеллируете к многопоточному программированию?
                      В таком случае, это вопрос организации взаимодействия и разделения данных между потоками.
                      Решил продемонстрировать, как я это вижу:
                      #include <thread>
                      #include <chrono>
                      
                      int func(const int& x)
                      {
                      	std::this_thread::sleep_for(std::chrono::seconds(1));
                      	if (x < 1)
                      		return -1;
                      	else return x;
                      
                      }
                      
                      int main(void)
                      {
                      	/*const*/ int i = 1;
                      	std::thread thr(foo, i);
                      	++i;
                      	thr.join();
                      }

                      В такой ситуации закомментированный const как раз снимает вопрос.


                      1. creker
                        22.04.2019 19:35
                        -1

                        Да даже без многопоточного. Достаточно положить объект себе куда-то в поле до лучших времен. Что с ним за это время может натворить мир вокруг никто не знает.


                        1. Static_electro
                          22.04.2019 19:37
                          +1

                          Так идея в том, что если ты получаешь конст-объект, то это ты не должен с ним что-то натворить.


                          1. creker
                            22.04.2019 19:44

                            Это уже извращения из стана плюсов. Если мы говорим об иммутабельности, а об этом и начался разговор, то этого недостаточно. Это не иммутабельность и const вроде бы никогда ей не считался. Это модификатор доступа, но не характеристика иммутабельности объекта.


                            1. NotThatEasy
                              22.04.2019 19:55
                              -2

                              Дело в количестве потоков исполнения и они есть, если я не ошибаюсь, во всех языках общего назначения, а не только в спп:

                              Если он 1 – то программа выполняется построчно, и пока поток выполнения находится в функции, объект назван его формальным параметром, то есть условно const int& x.

                              Если же их более, чем 1 – переменная действительно может измениться, ну тут уже смотрите, чтоб не было гонок.

                              Мы обсуждаем странное понятие иммутабельности – позвольте уточнить, что иммутабельные данные – это не коробка байт, которые не изменятся, даже если подача тока прекратится/коротнёт. Это коробка байт, которую можно открыть и посмотреть, но не трогать байты руками.

                              Если же мы обсуждаем изменение данных «извне» (напр., тупую ассемблерную подмену данных тем же артмани), то для того, чтоб программа корректно(?!) обрабатывала такие изменения, придётся использовать продвинутые техники.


                              1. creker
                                22.04.2019 20:02

                                Иммутабельность это иммутабельность. Это объект, который, единожды созданный, больше не изменяется. По крайней мере в рамках своего внешнего интерфейса. Нужно что-то изменить — вперед, делаем копию с изменением. Вот такая иммутабельность делает асинхронный код безопасным. А const модификатор это ограничение доступа к объекту, который, при этом, может меняться изменяться сколько влезет.

                                И чего вы к потокам привязались. Потоков может быть один, но код асинхронным. И запросто получишь ситуации, когда у тебя под ногами изменился объект. В современных языках с async/await и всеми этими вашими горутинами это обычное дело.


                                1. NotThatEasy
                                  22.04.2019 21:21

                                  Асинхронный пример принят, сам как-то не подумал.
                                  Непонятно следующее: каким образом /*фактическая*/ переменная, объявленная со словом const, может быть изменена в процессе выполнения программы?
                                  Большинство современных компиляторов плюсов выдадут ошибку, если в коде её значение попытаться изменить.


                              1. mayorovp
                                22.04.2019 23:57
                                -1

                                Потоки тут ни при чём. Берем функцию add_mul, с сигнатурой void add_mul(big_number &s, big_number const& a, big_number const &b) // s += a*b (на олимпиадах я такую любил, ибо элементарная операция), пишем add_mul(x, x, y) // x += x*y и приплыли. Поток всего один, но это не помогло.


                      1. mayorovp
                        22.04.2019 23:54

                        В такой ситуации закомментированный const как раз снимает вопрос.

                        А хотелось бы ошибку компиляции при "не снятом" вопросе...


  1. Speakon
    22.04.2019 16:13
    +1

    Как скоро появятся объявления рекрутёров с фразой «Опыт написания программ на Bosque от года»? ;)


    1. sumanai
      22.04.2019 19:45

      Меня больше бы позабавила эта фраза в резюме.


    1. OlegTar
      22.04.2019 19:46

      «от 5 лет»


  1. VGoudkov
    22.04.2019 16:26
    -1

    Kotlin? — нет, не слышали. Впрочем, у него есть фатальный недостаток


  1. RedCatX
    22.04.2019 19:07

    Всякий раз, когда очередной язык хотят сделать «более понятным для человека», они просто приближают его синтаксис к чему-то паскалеподобному. Так почему бы просто не взять Паскаль?


    1. math_coder
      22.04.2019 19:27
      +1

      Там переменные надо объявлять в отдельном блоке. Есть мазохисты, которым нравится, но остальные сильно против. Форвард-декларации — то же самое. И ещё много моментов, неадекватных с современной точки зрения.


      1. RedCatX
        23.04.2019 02:31

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


        1. TheKnight
          23.04.2019 03:25

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


        1. mayorovp
          23.04.2019 08:36

          Не легче. В этом самом отдельном блоке у переменной есть только имя и тип, и никакого контекста.


  1. skovpen
    22.04.2019 19:54

    а тут — перлом попахивает

    // 5.15 Merge
    var t = @[ 1, 2, 3 ];
    t<+(@[5])       //@[1, 2, 3, 5]
    t<+(@[3, 5])    //@[1, 2, 3, 3, 5]
    
    var r = @{ f=1, g=2, k=true };
    r<+(@{g=5})          //@{f=1, g=5, k=true}
    r<+(@{g=3, k=false}) //@{f=1, g=3, k=false}
    r<+(@{g=5, h=0)      //@{f=1, g=5, k=true, h=0}
    
    var e = Baz@{ f=1, g=2, k=true };
    e<+(@{g=5})          //@{f=1, g=5, k=true}
    e<+(@{g=3, k=false}) //@{f=1, g=3, k=false}
    e<+(@{g=5, h=0)      //error field not defined


  1. third112
    22.04.2019 22:02

    4) Вызов функций можно делать с указанием названия аргументов из сигнатуры функции, например: myfunc(x=1, y=2)
    Я правильно понял: вызов myfunc(x=1, y=2) полностью эквивалентен вызову myfunc(y=2, x=1) и вызову myfunc(1, 2), но не вызову myfunc(2, 1)? Кажется такое было в ассемблере OS 360/370 и то в макро. В каких других ЯП есть такое?


    1. sumanai
      22.04.2019 23:28
      +1

      В каких других ЯП есть такое?

      Вот тут в табличке выше есть.


    1. surly
      23.04.2019 13:09

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


    1. ksbes
      23.04.2019 15:09
      -1

      Kotlin? В нём, кстати, почти всё перечисленное в статье уже есть и выглядит весьма органично и дружелюбно, в отличии от.
      Чувствуется, MS решили запилить свой K# (как они запилили С# в ответ на Java). По мне — так лучше бы F# развивали, «отвязав» его от необходимости быть «совместимым» с С#.


    1. third112
      23.04.2019 18:55

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

       function  myfunc(x: integer=1; y : real=2.0) : real;
      то можно сделать вызов
      myfunc(y =3.16);
      а совсем роскошно будет выглядеть эквивалентный вызов
      myfunc(3.16);

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


  1. shikhalev
    22.04.2019 23:33

    Простите, а анонс точно не 1 апреля вышел?


  1. Shamanay
    23.04.2019 06:22
    -1

    Теперь можно пить шампанское «Боско» и писать на языке «Боско».


  1. Bytamine
    23.04.2019 12:25

    Страшен, как образы на картинах Босха.


  1. vba
    23.04.2019 17:51

    Все значения в Bosque являются неизменяемыми (immutable)

    Ну наконец-то они создали такой язык (F# не в счет).