Pull to refresh

Comments 114

Не могу сказать, что полностью изучил всю документацию, но возникает вопрос: в чем принципиальное отличие от numba ( https://numba.pydata.org/ ) с нескучным синтаксисом?

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

То есть в питоне нет инструментов, делающих то же самое?

Нет. Можно сделать exe с помощью PyInstaller, но это ничего общего с компиляцией не имеет. По сути это самораспоковывающийся архив, включающий интерпретатор питона и все библиотеки. Простейший Hello world в итоге весит не меньше 300мб, что накладывает ограничения на развертывание приложения и создаёт у пользователей недопонимание. А ещё подключение внешних зависимостей (файлы, звуки и т.п.) - отдельная проблема, не всегда тривиально решающаяся.

Никаких 300 Мб нет. SublieText вам в пример.

причем тут текстовый редактор и "компиляция" питона?

Есть. Как и pyarmor и куча подобных инструментов. Неприменимо, если проект не на чистом питоне, да и с ним они не всегда справляются. Любые внешние модули, gui и т.п. делают транспиляцию почти невозможной.

Я начал верить, что синтаксис Питона, и компиляция и скорость как плюсы, когда только появился Shed Skin.

Том, что с numba ты можешь работать сегодня. До тех пор пока mojo нет в открытом доступе, он конкурирует не с питоном, а с v, который тоже состоит из хайпа и невыполненных обещаний. (Только v можно качать)

Надежда, что благодаря Лэттнеру будет доведено до конца.

Дело в том, что питоновский int "отягощён" множеством дополнительных возможностей, как работа с большими числами или сравнение значений. Тип Int в Mojo наоборот очень простой и лёгкий, что позволяет значительно повысить скорость работы с ним.

Появление таких фич в долгосрочной перспективе сыграет очень плохою шутку. В т.ч. усложнит язык.

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

Надеюсь ошибаюсь.

Можно посмотреть на Скалу, где невозможно отличить int от Integer (язык сам выбирает, где делать боксинг/анбоксинг). В итоге высокопроизводительный код сильно проще написать на джаве и импортировать, чем аккуратно разбираться "а почему компилятор в этом месте не догадался, что int достаточно".

А почему они тогда не добавили int, который всегда примитивный?

Для простоты синтаксиса. У них всегда Int, который в байтовом коде по возможности будет приводиться к int. Есть специальный механизм (Type Specialization), который позволяет даже с дженериками писать так, чтобы была отдельная реализация с примитивами, но работает всё не очень прозрачно и простой синтаксис приводит к тому, что аккуратно сделать так, чтобы нигде не было боксинга несколько затруднительно.

При этом Type Specialisation вы должны сами написать вариант вашего класса для примитивного типа, или компилятор сможет сам?

Сам сможет.

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

Получается, если вы завели вектор интов, использовать цикл вроде for elem in vec:

Будет нежелательно?

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

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

Мне в этом плане нравится, как сделали в расте. Для инта всегда задается размер, типа i8, u8, u32, etc.

Чем это отличается от диалектов Паская начала 2000-х? Кроме "let и var" и интерфейсов к питоновским модулям?

  1. Нет программных скобок Begin и End (к сожалению скобочки { } тоже не завезли); не обязательность ";" в конце строк

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

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

  4. Вроде как есть универсальный тип Self который всегда обозначает тип текущего класса/структуры

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

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

  1. Малосущественное отличие, важно что операторные скобки в виде отступов присутствуют.

  2. Явное указание аргумента "self" тоже малосущественно. В Паскале идентификатор "Self" внезапно есть (https://wiki.freepascal.org/Self)

  3. В Питоне неограниченное количество аргументов передается с помощью *arg, **kwarg, где arg -- кортеж, kwarg -- словарь. Что с кортежами и словарями из текста статьи не ясно. Значения аргументов по умолчанию и именованные аргументы в вызове функций даже в Фортран завезли чуть ли не в конце 80-х.

  4. Ну есть и есть.

  5. Завезли (https://ru.wikipedia.org/wiki/PascalABC.NET). Процедурный тип был уже в конце 70-х, либо в начале 80-х.

  6. Должны, но не факт что есть. В Питоне типизация неявная, что позволяет создавать кортежи, списки и словари разнородных объектов, что является одной из его отличительных особенностей. Из статьи не ясно, как объявить кортеж разнородных переменных. Без такого кортежа нельзя создать ни разнородного списка через конструктор "list", ни словаря через "dict".

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

  1. Не понял о чём Вы (о каких скобках и в каком ЯП)

  2. В Паскале всё как раз цивильно:

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    // Self stands for the TForm1 class in this example
    Self.Caption := 'Test program';
    Self.Visible := True;
    end;

    В Mojo придётся писать так

    class Form1
    fn
    formCreate(self&, sender: Base): //честно, я хз какой у Mojo базовый тип классов
    // Self stands for the Form1 class in this example
    self.Caption = "Test program"
    self.Visible = true

  3. Вроде бы сравнение было про Паскаль, а не про Питон

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

  5. PascalABC.NET  - это всё-таки уже не совсем Паскаль (о котором Вы спрашивали - т.е. об Object Pascal 2000 года) - но штука может и интересная (тут равнение идёт на платформу ms dot net и требуется поддержка всех её возможностей на уровне CLR), только сейчас этот ЯП нафиг никому не сплющился - если на "классическом" Native Object pascal \ Delphi ещё кто-то да программирует - то новые поделки скорее всего обречены на забвение (ну если не привнесут в программирование чего-то революционно нового и пробивного, и не будет такой ЯП активно маркетиногово продвигаться). Да и был уже Delphi Prism от самих Embarcadero - только загнулся он давно (даже переезд на IDE Visual Studio ему не помог), как, впрочем, загнулись и все другие конверсии ЯП на платформу NET. По сути остался там в живых только родной C# (даже С++ for CLR загнулся).
    А про процедурный тип я и не спрашивал (я про анонимные функции сомневался - но кажется что были; а вот лямб точно в 2000 году не было, впрочем их тогда почти нигде не было, кроме горстки чисто функциональных ЯП)

  6. Почитал - есть кортежи и Mojo (списков и словарей пока нет) - в Паскале 2000 года их не было

За что минусы то - что я не так написал - объясните?

Так толком и не рассказали про язык программирования Mojo - вообще ни слова про его архитектуру - как он работает, что можно к нему подключать (ну про питоновские модули сказали, а ещё), где он работает (платформы и среды исполнения), чем код писать и т.п. Хотя упоминание Лэттнера как разработчика ЯП сразу делает намёк на LLVM и компиляцию в Native код и WASM.

Не понятно что тут будет с поддержкой библиотек других систем. Без них ЯП будет очень тяжело!

Название "Mojo" для меня как-то не очень серьёзно звучит - сразу китайщиной тянет!

Завезли новое объявление функций а типичный косяк дизайна синтаксиса питона оставили - необходимость явно передавать ссылку на объект "класса" (self) в качестве аргумента функции! Или я что-то не так понял?

Хотя указание ссылки на текущий тип "класса" через универсальный тип "Self" кажется очень интересным. Но как оно работает в классах наследниках - в какой реальный тип будет оборачиваться этот Self в унаследованных членах (в идеале - это должен быть тип наследника даже в наследованных членах - чтобы не приходилось делать явного приведения типов к наследованным типам для работы членами из наследованных классах; ну а с обратным неявным приведением к классам предков проблем не должно быть). Или я про этот тип "Self" тоже не так понял?

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

struct MyPair:
    var first: Int
    var second: Int

    # We use 'fn' instead of 'def' here - we'll explain that soon
    fn __init__(self&, first: Int, second: Int):
        self.first = first
        self.second = second

    fn __lt__(self, rhs: MyPair) -> Bool:
        return self.first < rhs.first or
              (self.first == rhs.first and
               self.second < rhs.second)

А вот эти двойные подчёркивания в функциях нахрена? Ну прям какой-то пережиток далёкого сишного прошлого - выглядит ну очень ужасно! И это во времена Kotlin... брррр....

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

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

Не раскрыта и тема распараллеливания и асинхронного программирования - хотя намекнули что у Mojo что-то очень крутое - а что - идите сами курите документацию - по мне, так какое-то неуважение к читателю получается!

Online песочницу для ЯП Mojo пока не завезли?

А вот эти двойные подчёркивания в функциях нахрена? Ну прям какой-то пережиток далёкого сишного прошлого

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

Но это же новый ЯП и он не стремится 100% перенять весь синтаксис Питона - нафига переносить элементы явно плохого и устаревшего дизайна! В утиль его тогда....

А чего в этом столь трагически плохого?
Придирка напоминает вот это:

Вообще никак не напоминает. А обоснованная критика - это всегда полезно!

Правда, обосновать с практической стороны кривые имена системных методов вряд ли удастся. Это просто некрасиво! Но это не является каким-то системным недостатком - ну раз так сделали (оставили) - ну и ладно - это не критично, дело привычки, но всё-равно на фоне современных ЯП - это просто бррррр.... как неприятно выглядит!

Так речь не просто о новом языке, а о языке, у которого основная киллер-фича — это совместимость с Python. Наоборот, было бы странно, если бы он такие вещи менял.

Да нет там никакой 100% совместимости - только по мотивам - попытка улучшить и осовременить - но при этом оставить явные косяки дизайна - брррр....

Как это нет... Пишешь в начале файла %Python3 и можешь писать на чистом пайтоне. Я так понимаю, будут вставки на пайтон-коде, то тут, то там, как раньше были ассемблерные вставки. И для целостности и читаемости кода конечно dunder-методы оставят.

необходимость явно передавать ссылку на объект "класса" (self) в качестве аргумента функции

Нет, не надо. В питоне это все происходит автоматов. При вызове car.drive() будет вызван метод `def drive(self)` у класса car

Синтаксис с объявлением типа возвращаемого значения и тела метода очень удивил

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

А вот эти двойные подчёркивания в функциях нахрена? 

Потому что это специальные функции, чтобы в коде можно было пользоваться `p1 + p2`, `p1 < p2`. Вам никто не запрещает объявить функцию less, но тогда ею нужно будет пользоваться как p1.less(p2)

Нет, не надо. В питоне это все происходит автоматов. При вызове car.drive() будет вызван метод `def drive(self)` у класса car

Я про определение функции "def drive(self)" - слово "передавать" было не правильным - правильнее "определять".

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

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

Потому что это специальные функции, чтобы в коде можно было пользоваться `p1 + p2`, `p1 < p2`. Вам никто не запрещает объявить функцию less, но тогда ею нужно будет пользоваться как p1.less(p2)

Это всё понятно и здорово, и мне уже пояснили, что это ещё наследие из Python - просто некрасиво очень выглядит с двойными подчёркиваниями (против самих функций-операторов ничего не имею), но в таких ЯП как C#, Scala, Kotlin это реализовано куда элегантнее. Да и тут можно было бы просто, хотя бы, сделать это хотя бы через явную реализацию специальных интерфейсов (не знаю есть ли они в Mojo - в Python городили метаабстракции над абстрактными классами для эмуляции интерфейсов; если в спецификации ЯП их нет - то это очередной камень в огород Mojo)

() -> Тип : Тело

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

А вот эти двойные подчёркивания в функциях нахрена?

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

Мне кажется еще довольно интересно:
- сокрытие на уровне класса, модуля. Как мы знаем, в Python с этим есть некоторые узкие моменты...
- если обычный класс сделали статичным, как поступили с метаклассами?

А вот эти двойные подчёркивания в функциях нахрена?

Полагаю, они это оставили как "эхо" Python-а:

https://docs.python.org/3/reference/datamodel.html#basic-customization

Может, чтобы Питонисты ринулись всей толпой в этот ЯП, из-за большей близости синтаксиса. :-D :-D

Сделали ЯП почти полным клоном (но без 100% совместимости) от Python - со всеми его "недостататками" и устаревшими подходами. В этом есть как плюсы (в основном для старого сообщества) так и минусы (в сосновом для новых адептов перебежчиков из других ЯП). Лично меня Mojio не привлёк :-( пока и Python сгодится для скриптинга

Спасибо за пояснение - было любопытно, но название ЯП всё-равно мне не нравится, ну тут ничего не поделаешь mojo для меня как сокращение от mahjong (Маджонг) - хоть и пишется иначе, а на слух сразу ассоциаця с mocha (Мокко как кофе) - хоть и произносится совсе не так как кажется по написанию - в общем просто неприятное восприятие - пока не углубишься в то, что это такое на самом деле и как же оно на самом деле произносится "Талисман"/"Магическая формула"/"Заклинание" ("Моуджоу"). В общем - это исключительно личное восприятие, я его не навязываю!

А в этом Mojo как и в Питоне присваивание переменной по прежнему неотличимо от объявления переменной? Если да то я чего-то не понимаю в этой жизни. Ну ладно структура кода пробелами, хрен с ней (хотя это и неудобно при копировании кода без спец.редакторов). Но когда один и тот же синтаксис используется и для присваивания, и для создания нового объекта - это же очевидный ляп. Ну сделали бы как в Go, там отдельный оператор := и все сразу встает на свои места.

 в этом Mojo как и в Питоне присваивание переменной по прежнему неотличимо от объявления переменной?

Нет - этот косяк питона исправили - для объявления теперь надо писать ключевые слова var или let - в т.ч. при объявлении полей в "классах"

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

Да, я понял после того, как вопрос задал :)

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

Отступы пробелами, ненужность скобочек и ";" в конце строк, а также отсутствие необходимости закрыващих команд вида end if итп, повлекших почти 2X-сокращение объема набираемого кода - вот все это обеспечило вхождение Python в Top-3 ЯП всех существующих рейтингов. Питону не хватало только скорости (и то больше психологически, чем ресурсно).

Mojo решает проблему скорости, добавив всего 5-ть новых сущностей: struct, fn, var, let и Python.import_module. Я их уже запомнил и готов применять. По-моему это гениально. Вангую появление нового лидера рейтингов ЯП.

"вот все это обеспечило вхождение Python в Top-3 ЯП всех существующих рейтингов"
сильное развитие data science, машинного обучения, вот что обеспечило его вхождение в топ, если бы не это, он так бы и оставался на своих позициях

Да, датастатанисты выбрали именно Питон - неужто воля случая и удачно подогнанные вовремя библиотеки? Ведь для работы с бигдата нужна высокая производительность - а ей питон похвастаться не может (не то что бы совсем всё плохо но всё же.... да и 10 лет назад как раз всё было куда плачевнее - когда он был чисто интерпретируемым)!

Это Вы ещё не познакомились с тем, что они там накрутили с управлением памятью и временем жизни объектов

А ещё совершенно не раскрыта тема управления памятью!

Python - это ЯП с управляемой памятью.

А как с этим дело обстоит у Mojo - он же, как я понял, native-яп так что тут с выделением, разделением (между потоками) и освобождением памяти, как в прочем и других ресурсов (например файловых)? Где и как выделятся память: куча/стек?

Есть ли сборщик мусора, подсчёт ссылок или тут rust-стиль контроля за областью видимости со всеми вытекающими?

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

А что у Mojo с null и вообще с нуллабельностью типов?

И что тут с расширенными инструкциями межпоточного неблокирующего взаимодействия и intrinsic инструкциями?

А ещё вопрос - раз ЯП Mojo строго типизированный то где же обобщённые типы (дженерики)?

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

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

Так-то и питон со строгой типизацией (пусть и динамической).
И уже пару-тройку лет там можно добавлять аннотацию типов, в том числе и дженерики.


Логично предположить, что и этот Mojo должен уметь в дженерики — раз уж он умеет использовать питонячий код, который может их содержать.

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

Можно то можно, только язык за аннотациями не следит - это исключительно подсказки для ИДЕ.

Пока не следит, но никто не мешает реализовать строго типезированный интерпретатор с jit.

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

Аннотации типов декораторами в Питоне это та ещё шляпа! Сложно, некрасиво и бестолково! И никто так не делает (раз можно не заморачиваться)! От того и бесполезно

Я не программист и не слишком плотно слежу за тенденциями в IT-сфере, но у меня возник вопрос:

«let — неизменяемая переменная»

Раньше, емнип, это называлось «константа». Почему сейчас я всё чаще вижу термин «неизменяемая переменная»? Хотя это звучит как «сухая вода» или «холодный огонь», т.е. оксюморон.

Судя по описанию (кстати, кто Вам мешал погуглить?) let объявляет однократно инициализируемую переменную. То есть Вы можете назначить ей значение при объявлении, а можете потом, но один раз.
Финт ушами и не очень понятно в чем мегакрутизна, но вот так вот.

Если б я понимал, как правильно сформулировать вопрос, я бы погуглил, конечно.
Да и у меня вопрос не в том, как это работает. У меня удивление терминологией. «Неизменяемая переменная» — два слова, которые противоречат друг другу.

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

Да я-то, вообще, лингвист. :) Так что если вам, программистам, норм, то и хорошо.

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


К чему это я? Само слово переменная (как и его английский аналог variable — см. также variant, variate, variance) подразумевает возможность смены значения. Поэтому "неизменяемая переменная" — это действительно оксюморон. Логичнее было бы использовать слово "константа" или "инвариант".

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

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

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

Конечно можно попробовать термины "Поле" и "Реквизит" - но они уже болье ассоциируются с другим назначением. Хотя вот в описании ЯП Kotlin я встречал такое понятие "Локальное свойство" - но слишком длинно (да и контекст там связан с особой частной фишкей языка).

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

Думаю тут не стоит пытаться придираться - уж как устоялось так устоялось в лексиконе!

В функциональных языках их ещё называют local bindings, ну и они там мутабельными в принципе быть не могут.

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

В остальных случаях если честно все let/val объявления по сути что добавление модификатора (аннотации) readonly - но чаще всего это полная хрень для составных данных (если их типы изначально не объявлены как readonly) - т.е. это лишь защита переменной/поля от изменения - но не защита от изменения объекта её содержимого! Вот куда правильнее терминология mutable/unmutable идущая из функционального программирования - вот unmutable объект всегда 100% защищён от изменений! И переменный/поля по умолчания обычно объявляются как unmutable - и их значения не могут изменяться!

Ну а let/val хоть и неизменяемая переменная, но объект внутри неё вполне изменяемый - поэтому всё-таки переменная. Даже порой можно такой переменной задать значение ссылкой на примитивный тип, хранимый в другой, уже изменяемой, переменной - и тогда даже примитивное значение можно менять через эту другую переменную. Но не знаю - поддерживает ли Mojo такой хук

Из Вашего объяснения я понял (поправьте, если не так), что

переменная — изменяется и по значению, и по ссылке;
неизменяемая переменная — не изменяется по значению, но изменяется по ссылке;
константа — не изменяется ни по значению, ни по ссылке.

Ок, я понимаю, как это работает. Но терминология всё равно странная.
Впрочем, я лингвист, а не программист. :)

Да в целом всё правильно. Но константа ещё и на стадии компиляции должна получить обязательно значение. А в рантайме их и вовсе не будет!

Вот так можно (псевдоко код):

let value = ReadUserKey()

а так нельзя

const value = ReadUserKey()

а вот так можно (если бы Mojo такое поддерживал, как это есть в некоторых других ЯП)

def add(const a : Int) -> const Int : a +1

const v1 = 1

const v2 = add(v1) //v2 = 2

const v3 = add(v2*v2) //v3 = 5

let v = arr[v3] //где arr - какой-то массив, желательно в стеке, а если ещё и константный то вместо let тоже можно использовать const

Все эти выражения могут быть вычислены на стадии компиляции и такое бы прокатило бы, например в ЯП С++

Просто применение констант вместо неизменяемых переменных это обычно ещё один элемент оптимизации компиляции - и константы не обязаны быть примитивными типами

Скорее так:


Константа — идентификатор для заранее известных неизменных данных;
Неизменяемая переменная — идентификатор для заранее неизвестных, определяющихся в процессе работы, данных, не позволяющий их менять;
Изменяемая переменная — идентификатор для заранее неизвестных данных, позволяющий их менять.


Из-за того, что слова однокоренные, звучит странно, но эти два слова к разным свойствам относятся.

Признаемся честно - автор поста хрен спорол неудачно выразился.
Но так как а) язык новый и б) документация на него, соответственно, пока неуклюжая и б) это первый пост автора, то простим ему.
"Других определений у нас для вас нет".

Ну сами понятия-то не новые, в других языках уже многократно появлялись. Так что о деталях применительно к Mojo можно только спекулировать, а вот о терминологии в целом можно и предметно дискутировать.

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

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

Замечу ещё тот факт, что промежуточный язык IR для LLVM (а Mojo на нём строится) вообще технически не поддерживает изменяемые переменные - а для их реализации использует хитрую техники с фи-операцией

В JavaScript есть и const, и let, и var. Компилятора при этом нет.

И let, и var - это переменные, т.е. которые могут меняться.

Const - это не переменная и быть ею не может по определению.

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

Ох, раньше ойти было технической специальностью, а теперь споры сплошь филологические

Не понял, чем он не корректен?

У JavaScipt кстати есть компилятор (он может компилировать некоторые функции, в процессе их использования, в рантайме).

Но интерпретатор - это другая тема, да он может и в рантайме осуществлять контроль (жертвуя производительностью) - но лучше не заводить тему про переменные в JavaScript - там такой хаос в поведении - мама не горюй! Нет - всё по правилам - вот только очень уже неоднозначно воспринимаемые эти правила (ветьеватые)

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

struct Complex:

Да как вы задрали классы структурами называть. Какая-то старая хрень пролезла из Сишечки в Плюсики, и все плюсовые говнокодеры аккуратно пишут struct вместо class, чтобы было сложнее.

Уже дали определение: структуры - это только данные. Классы - данные плюс методы. Но нет, мы будем умничать и оправдывать себя рассказывая про дефолные режимы контроля доступа.

А если я рядом со структурой напишу функцию которая с ней работает и её изменяет, где будет ваш ООП-бог?

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

Самое правильное разделение в C#

  1. Структура - это объектное хранилище (кстати особый вид класса, производного от класса ValueType), размещаемое на стеке (как смамостоятельное значение; или просто скоуп данных в составе другого хранилища, размещаемого там же где и этот хранилище-владелец). То есть Структура по сути это тоже класс (и в .NET нет структур) просто с особой обёрткой для оптимизации использования и удобства кодирования. И Структура - это не тип - а лишь синтаксический сахар.

  2. Класс - это объектное хранилище всегда размещаемое только в куче.

Потом ещё добавили record который позже стал record struct и record class что стало логичнее восприниматься - теперь record луче воспринимать как модификатор (а просто record как упрощённый синтаксический сахар над record struct) для построителя соответствующего класса (с доп. наполнением и некоторыми добавками к синтаксису). Хотя, на мой взгляд, можно было обойтись и просто атрибутом компиляции а-ля "[RecordAtribute]". То есть никаких новых типов - всё те же классы, только иммутабельный

Ну а последний писк это ещё и "readonly struct", "ref struct", "readonly ref struct" и даже "readonly record struct" - тоже по сути ничего не меняющие - тот же класс, производный от класса ValueType - только с до ограничениями. Честно не знаю в чем принципиальная разница в "record" и "readonly struct" и тем более с "readonly record struct" (ну кроме того, что модификатор record даёт дополнительные фишки синтаксического сахара с кодогенерацией, т.е. это скрытый макрос) - во всех случаях объект будет иммутабельный, а в чём отличия в иммутабельности я у них я не знаю.

А вот "ref struct" (и "readonly ref struct)" куда интереснее - этот всё тот же производный класс от ValueType но с возможностью размещения только в стеке (и он может входить в состав полей других классов, но только если они тоже "ref struct" т.е. тоже только размещаемые с стеке) - причём строго принудительно (боксинг не допускается).

Все эти модификаторы в C# лишь хинты для компилятора - в итоге будет всегда класс - но вот операции над ним будут оптимизированы согласно заданным ограничениям! И я не знаю ещё языки программирования (кроме C++, ну отчасти Rust) где можно было бы задавать подобные оптимизации

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

На сайте разработчиков Mojo есть пример с умножением матриц.

https://docs.modular.com/mojo/notebooks/Matmul.html

Для этого примера программа на Mojo в 8.6 раз быстрее питона.

Набросал скрипт этого примера на Lua, который в 18.9 раз быстрее питона.

Если кто найдет ошибки, то пишите, исправлю результат.

Это текст скрипта:

local function Matrix(X,rs,cs)
	local A={}; A.rs=rs; A.cs=cs;
    for m=1,rs do local a_m=(m-1)*cs; for n=1,cs do  A[a_m+n]=X end	end
return A;
end

local function matmul_lua(C,A,B)
    for m=1,C.rs do local c_m=(m-1)*C.cs; local a_m=(m-1)*A.cs;
        for n=1,C.cs do  local c_mn=c_m+n
            for k=1,A.cs do  local b_k=(k-1)*B.cs;
			 	 C[c_mn]=C[c_mn]+A[a_m+k]*B[b_k+n]
			end
		end
	end
end

local A=Matrix(1.,128,128);
local B=Matrix(1.,128,128);
local C=Matrix(1.,128,128);

local t=os.clock()
matmul_lua(C, A, B);
local t=os.clock()-t;
gflops=(2*(128*128*128)/t)/1e9
print(gflops)

Думаю мериться попугаями пока рановато - Mojo только появился!

Матрицы на чистом Python умножают только в учебном процессе или чтобы показать черепашью скорость интерпретатора. Стандарт практики - использовать в Python либу numpy (внутри С++, Fortran и др), которая умножает матрицы в десятки раз быстрее. Нам, датасатанистам, вообще все равно какой язык умножает, лишь бы делал это быстро и "не выходя из Python, в блокноте". Mojo, судя по обещаниям, делает это самым питонячим способом из придуманных, при этом заявляется что даже быстрее С/С++.

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

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

В примере  "генерации множества Мандельброта, скомпилированное приложение на языке Mojo при выполнении в облаке AWS (r7iz.metal-16xl) оказалось .. в 35 тысяч раз быстрее приложения на Python при использовании штатного CPython 3.10.9. "

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

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

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

Так как пишу на СИ то нет проблем организовать параллельное вычисление. Хотелось бы выяснить реальные возможности языка Mojo на одинаковом железе.

Будем ждать, когда выложат в свободный доступ.

Интересно узнать превосходит ли  Mojo вот это:

Опубликован релиз языка программирования Julia 1.9, сочетающего такие качества как высокая производительность, поддержка динамической типизации и встроенные средства для параллельного программирования. Синтаксис Julia близок к MATLAB с заимствованием некоторых элементов из Ruby и Lisp. Метод манипуляции строками напоминает Perl. Код проекта распространяется под лицензией MIT. (Не надо записываться в очередь, чтобы использовать)

Ключевые особенности языка:

  • Высокая производительность: одной из ключевых целей проекта является достижение производительности близкой к программам на языке Си. Компилятор Julia основан на наработках проекта LLVM и генерирует эффективный нативный машинный код для многих целевых платформ;

  • Поддержка различных парадигм программирования, включая элементы объектно-ориентированного и функционального программирования. Стандартная библиотека предоставляет в том числе функции для асинхронного ввода/вывода, управления процессами, ведения логов, профилирования и управления пакетами;

  • Динамическая типизация: язык не требует явного определения типов для переменных по аналогии со скриптовыми языками программирования. Поддерживается интерактивный режим работы;

  • Опциональная возможность явного указания типов;

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

  • Возможность прямого вызова функций из библиотек на языке Си без дополнительных прослоек.

А ещё в Julia есть пакет PyCall, который позволяет делать так:

применение питонячьих библиотек в Julia

И обратите внимание на шикарную совместимость с Jupyter Notebook!

Нашел дополнение к статье:

Задействование дополнительных аппаратных механизмов для ускорения вычислений даёт возможность добиться производительности, при интенсивных вычислениях превосходящей приложения на C/C++. Например, при тестировании приложения для генерации множества Мандельброта, скомпилированное приложение на языке Mojo при выполнении в облаке AWS (r7iz.metal-16xl) оказалось в 6 раз быстрее реализации на C++ (0.03 сек. против 0.20 сек.), а также в 35 тысяч раз быстрее приложения на Python при использовании штатного CPython 3.10.9 (0.03 сек. против 1027 сек.) и в 1500 раз быстрее при использовании PYPY (0.03 сек. против 46.1 сек.).

При оценке производительности в области решения задач машинного обучения, AI-стек Modular Inference Engine, написанный на языке Mojo, по сравнению с решением на базе библиотеки TensorFlow оказался на системе с процессором Intel в 3 раза быстрее при обработке языковой модели, в 6.4 раза быстрее при выполнении модели формирования рекомендаций и в 2.1 раза быстрее при работе с моделями для обработки визуальной информации. При использовании процессоров AMD выигрыш при использовании Mojo составил 3.2, 5 и 2.2 раза, а при использовании процессоров ARM - 5.3, 7.5 и 1.7 раз, соответственно. Решение на базе PyTorch отстало от Mojo в 1.4, 1.1 и 1.5 раз на CPU Intel, в 2.1, 1.2 и 1.5 раз на CPU AMD и в 4, 4.3 и 1.3 раза на CPU ARM.

Ну честно говоря не понятно про язык вообще ничего.

Заявленные характеристики производительности возможны в случаях:
- подделки (немасштабируемый костыль) под конкретный use-case
- какое-то концептуальное (например data-flow / порт в OMP / ... ) распараллеливание в языке.
- (все компиляторописатели последние 20 лет занимались фигнёй и .... - ну это так для проформы момент).
Про концептуальное распараллеливание в статье ни слова. Результатов spec тестов нету - значит ли это, что реализовался первый вариант?

2. Какая система типов в языке? Хотя бы "объекты" или "структуры с интерфейсами (трейтами \ тайпклассаи \ ...)"?

3. Как в типизированный язык импортируются модули из нетипизированного (Python)?

4. Ну и да всякие вопросы типа: это будет native компиляция с честным ffi в С или какая-то платформа? Пакетный менеджер? Ну и куча других вопросов, с которых по-хорошему начинать надо, но они вообще за рамками статьи остались.

Вот как они программу на плюсах написали в 6 раз медленнее чем на Mojo?
И даже TensorFlow в 3 раза обогнали?!

Нет, я могу написать даже на питоне программу быстрее чем на C. Только это будет плохая программа на C :)
Или у них ошибка в бенчмарках, или программа на C/C++ немного не оптимизирована

Ну если на Mojo обращаться к библиотеке, написанной на asm с экстремальной оптимизацией..... но что мешало к ней же обращаться на С/С++ - остаётся только проблема разной работы оптимизаторов (и разного применения инструкций, кои их для процессоров сейчас туева куча) - и тут да - чтобы не быть голословным - нужно asm инструкций обоих программ!

Бенчмаркомерилки это делают так:
1. Ищем конкретный случай под SIMD (SSE или AVX), который современные компиляторы не распознают - а они довольно плохо SIMD делают, в том числе потому, что не знают вам Vec<Int> - он обычно на 2 инта или обычно на 2000 интов?
2. Конкретно для этого случая вставляем костыль "распараллель под SIMD" (с пре-лупом, внутренним распараллеленным под SIMD циклом и пост-лупом).
3. Добавляем этот бэнчмарк и хвастаемся какой крутой наш компилятор.

Вот она, волна рекламы дошла от зарубежного интернета до хабра

По описанию выглядит как свифт с синтаксисом от питона

зачем каждый раз писать "придет на смену Python"...
не понимаю. Дедукция же...

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

Смелое, но ошибочное обобщение. Продолжу в том же духе: Need for speed есть у всех и на всех ЯП. Но это не просто "жажда скорости". Причина уважительна и более глубинная. Чем более быстр ЯП - тем в большем спектре задач он найдет применение, а специалист в нем - будет себя чувствовать более востребованным (больше получать в итоге).

Сейчас при выборе "стека для прода" - Питон вычеркивают на первом же совещании, потому что бенчи 100:1 с С++/Go/Rust итд видели все айтишники. Возразить некому и нечем.

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

Кто-то берется предсказать что будет со всеми рейтингами ЯП, если все JS-семейство превратить в одну строку? Что интересно - любой результат такого изменения снизит накал соревнования. А значит он невыгоден всем спонсорам рейтинга: организаторам, журналистам, школам, инфлюэнсерам итд. Даже JS-девопсы будут ныть. Поэтому рейтинги ЯП, со всей их JS-дичью, инородными участниками типа SQL, HTML, Bash итд, прикрытыми личиной "полноценности" - хорошее чтиво на усладу, но никак не руководство к выбору. А вот Mojo, если это правда - мотивирует.

Питон вычеркивают на первом же совещании, потому что бенчи 100:1 с С++/Go/Rust итд видели все айтишники

Numba и Cython сокращают этот разрыв, а большее там и не требуется. Mojo легко развертывается, но только ради этого менять ЯП будет трудно.
Другими словами, Mojo не радикально лучше Python, чтобы переходить на него.


Но журналисты против: это смешает все карты обзорщиков.

Лично я только за хайп! Это помогает прогрессу.

Питон вычеркивают на первом же совещании, потому что бенчи 100:1 с С++/Go/Rust итд видели все айтишники

Совершенно некорректное сравнение - Питон и указанные ЯП созданы для решения разных задач. Но, Mojo может оттняуть на себя некоторый небольшой кусок пирога от задач, типично решаемых на Питоне (в основном из-за библиотек и сложившихся реалий), но требующих крайне высокой производительности - из-за чего чаще всего их решают на C++

Корректнее было бы сравнить Python и C#, Scala, Kotlin, Java....

Хотя, по-чесноку, надмножество ЯП надо считать одним ЯП.

Mojo не совсем надмножество - у него нет 100% обратной совместимости (даже если пренебречь декларацией типов)

А если говорить о JS - то ни Scala ни Kotlin не стоит считать надмножествам JS (думаю TypeScript тоже не стоит - хотя тут много общего, если убрать типизацию)

Для системного программирования есть Rust

Можно Kotlin Native попробовать

Но вообще там C/С++ рулят и это надолго. Миру сейчас важнее прикладная кросс-разработка, упрощение распараллеливания и быстрое создание красивого фронтэнда

Для системного программирования есть Rust

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


Можно Kotlin Native попробовать

Kotlin похож на С++ и, если он будет таким же кроссплатформенным и быстрым, то почему бы и нет.


Но вообще там C/С++ рулят и это надолго

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


Миру сейчас важнее прикладная кросс-разработка, упрощение распараллеливания и быстрое создание красивого фронтэнда

Да, это всегда важно было.

Системное программирование - это Вам не прикладное программирование - тут стенания на каждом шагу - работающим в этой области давно пора привыкнуть!

Kotlin похож на С++ 

Я бы не сказал, что он похож Единственное что они оба из класса фигурно-скобочных ЯП. Ну и корни ООП у них схожие (но по факту сильно отличающиеся). Kotlin Native безусловно больше похож на C++ т.к. перенимает от него часть прямой работы с памятью, но не более того.

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

Навряд ли уже появится. Сейчас делается ставка на Rust - но его не так легко принять. Думаю тут C/C++ будут и далее доживать свой век ещё долго - просто их область прямого применения будет сужаться и сужаться. Остальные ниши будут заполнять ЯП прикладного уровня. Ну и кодогенерация для особых случаев в LLVM (или на С/С++) из более высокоуровневых ЯП (но чистые сишники их никогда не примут и будут медленно вымирать вместе с оставшейся нишей С/С++).

Да, это всегда важно было.

Не всегда, а лишь последние лет 5-10 - и это ещё не кульминация - её стоит ждать ещё лет через 20-30. Но сишникам в эту нишу уже не просочиться - хотя небольшой частью текущего пирога они будут ещё долго питаться (в основном в области баз данных, и сверх быстрых распределённых вычислений)

Навряд ли уже появится

Не, я оптимист, буду ждать замену С, С++ и Rust. Хотя время действительно упущено, ей бы еще в нулевых появиться.


Остальные ниши будут заполнять ЯП прикладного уровня

Есть такая ниша, как управление процессами в режиме реального времени (транспорт, производство и т.д.). Современные ЯП прикладного уровня с их GC и VM пока не тянут, а С/С++ дают слишком много ошибок (в больших проектах). И эта ниша будет только увеличиваться. Кто ее займет — будем посмотреть.

Есть такая ниша, как управление процессами в режиме реального времени (транспорт, производство и т.д.). Современные ЯП прикладного уровня с их GC и VM пока не тянут

Поясните, почему не тянут. На мой взгляд этот область программирования как раз отлично подходит для автоматизации на более высокоуровневых ЯП, чем C++. Да, некоторая часть прямого взаимодействия с аппаратурой требует вмешательства на ЯП системного уровня - но это только драйверы и библиотеки API прямого взаимодействия (да и то очень ограниченно, даже на C# есть небезопасное управление памятью, чтобы работать с драйверами, и если драйверы писать на современный лад, то этого вполне достаточно). Всё остальное вполне можно выносить на прикладной уровень и управляемую память.

Это позволяет вынести узкие участки на системный уровень с минимальным кодом, который обложить тестами. А остальное всё реализовывать на более комфортных ЯП с меньшими издержками на разработку (и с незначительными издержками на производительность).

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

Поясните, почему не тянут. На мой взгляд этот область программирования как раз отлично подходит для автоматизации на более высокоуровневых ЯП, чем C++

Конечно на высокоуровневых ЯП разрабатывать такое ПО намного проще, чем на C++, но даже они слишком: подвержены ошибкам, требуют остановки работы системы для очистки памяти через GС, сложны сами по себе и т.д. Что, вкупе с требованиями по отличному знанию C/C++, задирает требования к квалификации разработчиков до небес. Другими словами, они просто не отвечают современным требованиям.


Понятно, что на безрыбье и рак рыба, но все таки потенциал для роста есть. А уж будет ли он реализовав — непонятно, сейчас пока все корпорации пропихивают свои технологии/ЯП, невзирая на их качество.


И Rust я бы не стал отвергать

Раз уж корпорации взялись за Rust, то скорей всего он взлетит. Всё лучше (надежней), чем C++.

Кстати, была как-то попытка создать ЯП, объединяющий в себе плюсы высокоуровневых и низкоуровневых языков — Ада. Но он не взлетел (по многим причинам).

Егор, Вы - молодец, статья получилась довольно полезная и информативная

Sign up to leave a comment.

Articles