Mojo обновления надо регулярно отслеживать.
Пламенный привет посетителям этой страницы, пришедшим из социальных сетей, да и всем остальным тоже!
В апреле 2021-го года наблюдал удивительное явление: обильный поток посетителей из 4-х социальных сетей. В связи с этим настоятельно рекомендую всем неоднократно и регулярно посещать сайт rtbsm.ru — там в общих чертах изложена Российская Теннисная Балльная Система Марии (Шараповой).
Приглашаю всех полюбоваться на Фото и Видео красавицы Марии — надеюсь, что Вы поделитесь адресом сайта rtbsm.ru с друзьями и знакомыми.
Главная проблема — известить Марию, чтобы она лично как можно скорее заявила на весь мир о РТБСМ.
Mojo обновления в 2024-м году появляются регулярно: в среднем примерно раз в месяц, поэтому надо их отслеживать и обновлять свою версию MOJO.
Но разработка языка MOJO далека от завершения, поэтому я откладываю его освоение: Python и ранняя версия компилятора MOJO у меня установлены, однако на новом ноутбуке использую Windows 11, поэтому жду версию компилятора для Windows.
Версия от 13-го сентября 2024-го года: со страницы https://docs.modular.com/mojo/changelog#v245-2024-09-13 :
Mojo список изменений
Это список изменений в языке Mojo, стандартной библиотеке и инструментах.
Чтобы проверить текущую версию, запустите
mojo --version
. Чтобы обновить версию Mojo для вашего проекта с помощьюmagic
менеджера пакетов, следуйте инструкциям в разделе Обновить пакет, чтобы обновитьmax
пакет.Переключиться на Magic
modular
Средство командной строки устарело (см. Как его удалить - https://docs.modular.com/max/faq#if-you-installed-with-modular-deprecated-1 ). Мы рекомендуем Вам теперь управлять своими пакетами с помощьюmagic
(https://docs.modular.com/magic), но Вы также можете использовать conda (https://docs.modular.com/magic/conda).версия 24.5 (2024-09-13)
✨ Основные моменты
Вот краткое изложение некоторых основных изменений в этом выпуске, с более подробной информацией в следующих разделах:
- Mojo теперь поддерживает совместимость с Python 3.12.
- Набор автоматически импортируемых объектов (типов, псевдонимов, функций) в пользовательские программы Mojo был значительно сокращен. Это может нарушить работу существующего пользовательского кода, поскольку пользователям необходимо будет явно импортировать то, что они используют, для случаев, которые ранее автоматически включались ранее.
print()
теперь требуется, чтобы его аргументы соответствовалиFormattable
признаку. Это позволяет по умолчанию выполнять эффективную запись на основе потока, избегая ненужных распределений кучи промежуточных строк.- Новая встроенная
input()
функция выводит необязательное приглашение и считывает строку из стандартного ввода тем же способом, что и Python.- Mojo теперь позволяет неявно определять переменные внутри
fn
так же, как это разрешено вdef
. Ключевое словоvar
по-прежнему разрешено, но теперь необязательно.- Mojo теперь выявляет нарушения «исключительности аргументов» из-за псевдонимов. Mojo требует, чтобы ссылки (включая неявные ссылки из-за аргументов
borrowed
/inout
), если они изменяемы, ссылались на уникальные (не псевдонимы) объекты. В версии 24.5 это предупреждение, но в последующих версиях оно будет преобразовано в ошибку.- Mojo теперь поддерживает «условное соответствие», когда некоторые методы в структуре имеют дополнительные требования к свойствам, которых нет в самой структуре.
DTypePointer
,LegacyPointer
, иPointer
были удалены. ИспользуйтеUnsafePointer
вместо этого. Функции, которые ранее требовалиDTypePointer
теперь требуют эквивалентаUnsafePointer
. Для получения дополнительной информации об использовании указателей см. Небезопасные указатели в Руководстве Mojo.- Существует множество новых API стандартной библиотеки с новыми функциями для строк, коллекций и взаимодействия с файловой системой и средой. Изменения перечислены в разделе стандартная библиотека.
- Расширение VS Code теперь поддерживает пакет MAX SDK для VS Code, который автоматически загружается расширением и используется для всех функций Mojo, включая сервер Mojo Language Server, Mojo debugger, Mojo formatter и многое другое.
mojo test
теперь для запуска модульных тестов используется компилятор Mojo. Это решит проблемы с компиляцией, которые иногда возникали, а также улучшит общее время выполнения тестов.Языковые изменения
- Mojo теперь допускает неявные определения переменных внутри a
fn
тем же способом, который был разрешен в adef
. Ключевое словоvar
по-прежнему разрешено и по-прежнему обозначает объявление новой переменной с областью видимости (как вdef
, так и вfn
). Это делаетfn
иdef
более похожими, но они по-прежнему отличаются другими важными аспектами.- Mojo теперь диагностирует нарушения «эксклюзивности аргументов» из-за псевдонимов ссылок. Mojo требует, чтобы ссылки (включая неявные ссылки из-за
borrowed
/inout
аргументов) имели уникальные ссылки (без псевдонимов), если они изменяемы. Это важно для безопасности кода, поскольку позволяет компилятору (и читателям кода) понимать, где и когда изменяется значение. Это также полезно для оптимизации производительности, поскольку позволяет компилятору знать, что доступ через неизменяемые ссылки не может изменяться за кулисами. Вот недопустимый пример.:fntake_two_strings(a: String,inout b: String): # Mojo knows 'a' and 'b' cannot be the same string. b += a fninvalid_access(): var my_string = String() # error: passing `my_string` inout is invalid since it is also passed # borrowed. take_two_strings(my_string, my_string)
Это похоже на проверку эксклюзивности Swift и на язык Rust иногда известный как «сглаживание xor или изменяемость». Тем не менее, Mojo детали реализации несколько отличаются, потому что время жизни встроено в типы.
Это предупреждение в выпуске 24.5, но в последующих выпусках оно будет обновлено до ошибки.
Примечание- Mojo теперь поддерживает «условные соответствия», когда некоторые методы структуры предъявляют дополнительные требования к характеристикам, которых нет у самой структуры. Это выражается через явно объявленный
self
тип.:structGenericThing[Type: AnyType]:# Works with anything # Sugar for 'fn normal_method[Type: AnyType](self: GenericThing[Type]):' fnnormal_method(self):... # Just redeclare the requirements with more specific types: fn needs_move[Type: Movable](self: GenericThing[Type],owned val: Type): var tmp = val^# Ok to move 'val' since it is Movable ... fnusage_example(): var a = GenericThing[Int]() a.normal_method()# Ok, Int conforms to AnyType a.needs_move(42)# Ok, Int is movable var b = GenericThing[NonMovable]() b.normal_method()# Ok, NonMovable conforms to AnyType # error: argument type 'NonMovable' does not conform to trait 'Movable' b.needs_move(NonMovable())
Условное соответствие также работает с методами dunder и другими вещами.
- В качестве особой формы «условного соответствия» инициализаторы в структуре могут указывать конкретные привязки параметров, которые следует использовать в типе их
self
аргумента. Например:@value structMyStruct[size: Int]: fn__init__(inoutself: MyStruct[0]):pass fn__init__(inoutself: MyStruct[1], a: Int):pass fn__init__(inoutself: MyStruct[2], a: Int, b: Int):pass deftest(x: Int): a = MyStruct()# Infers size=0 from 'self' type. b = MyStruct(x)# Infers size=1 from 'self' type. c = MyStruct(x, x)# Infers size=2 from 'self' type.
- Mojo теперь поддерживает именованные привязки результатов. Именованные привязки результатов полезны для прямого помещения результатов функций в выходной слот функции. Эта функция обеспечивает большую гибкость и гарантии при помещении результатов функций по сравнению с «гарантированной» оптимизацией именованных возвращаемых значений (NRVO). Если
@register_passable
результат привязан к имени, значение результата становится доступным как изменяемая ссылка.fnefficiently_return_string(b: Bool)-> String as output: if b: output ="emplaced!" mutate(output) return return"regular return"
Если бы мы использовали временный объект для
output
вместо этого, нам нужно было бы переместиться в слот результата, что не сработало бы, если бы тип результата был неперемещаемым.В функции с именованным результатом
return
может использоваться без операнда для обозначения выхода из функции или может использоваться как обычно для указания возвращаемого значения функции. Компилятор выдаст ошибку, если результат не инициализирован во всех обычных случаях выхода из функции.__setitem__()
теперь работает со списками переменных аргументов, такими как:structYourType: fn__setitem__(inoutself,*indices: Int, val: Int):...
Компилятор Mojo теперь всегда передаёт «новое значение», устанавливаемое с помощью последнего ключевого аргумента
__setitem__()
, например, превращаяyourType[1, 2] = 3
вyourType.__setitem__(1, 2, val=3)
. Это исправляет ошибку № 248.- Менеджеры контекста Mojo, используемые в областях кода, которые могут вызывать проблемы, больше не нуждаются в определении «условной» функции выхода в форме
fn __exit__(self, e: Error) -> Bool
. Эта функция позволяет контекстному менеджеру условно перехватывать и обрабатывать ошибку и разрешать функции продолжать выполнение. Это полезно для некоторых приложений, но во многих случаях условный выход делегируется функции безусловного выходаfn __exit__(self)
.Конкретно, это позволяет определятьwith
области, которые безоговорочно распространяют внутренние ошибки, позволяя использовать такой код, как:defmight_raise()-> Int: ... deffoo()-> Int: with ContextMgr(): return might_raise() # no longer complains about missing return defbar(): var x: Int with ContextMgr(): x = might_raise() print(x)# no longer complains about 'x' being uninitialized
async
функции теперь поддерживают результаты только для памяти (например,String
,List
, и т.д.) Иraises
. Соответственно, оба вариантаCoroutine
иRaisingCoroutine
были изменены на принятиеAnyType
вместоAnyTrivialRegType
. Это означает типы результатовasync
функций не обязательно должны бытьMovable
.asyncfnraise_or_string(c: Bool) raises -> String: if c: raise"whoops!" return"hello world!"
Обратите внимание, что
async
функции пока не поддерживают косвенные вызовы,ref
результаты, и конструкторы.- В
Reference
типе (и многих итераторах) теперь используются параметры только для вывода для представления изменчивости в течение их жизненного цикла, что упрощает интерфейс.- Переменная среды
MOJO_PYTHON
может указывать на исполняемый файл, чтобы привязать Mojo к определенной версии:exportMOJO_PYTHON="/usr/bin/python3.11"
Или виртуальная среда, позволяющая всегда иметь доступ к этим модулям Python:
exportMOJO_PYTHON="~/venv/bin/python"
MOJO_PYTHON_LIBRARY
все еще существует для сред с динамическимlibpython
но нет исполняемого файла Python.- Семантика псевдонимов указателей в Mojo изменилась. Изначально Mojo использовал семантику псевдонимов указателей и производных указателей, как в C. Однако семантика C содержит много истории и «балласта», которые не нужны в Mojo и усложняют оптимизацию компилятора. В целом язык обеспечивает более строгий набор инвариантов для псевдонимов указателей с учётом времени жизни и эксклюзивных изменяемых ссылок на значения и т. д.Теперь запрещено преобразовывать значение, не являющееся указателем, полученное из указателя, выделенного Mojo, например целочисленный адрес, в значение, являющееся указателем. «Полученное» означает, что биты значения, не являющегося указателем, совпадают с битами исходного значения указателя. Соответственно, конструктор
UnsafePointer
с ключевым словомaddress
в качестве аргумента был удалён.По-прежнему возможно выполнить это преобразование в определенных случаях, когда это абсолютно необходимо, например, для взаимодействия с другими языками, такими как Python. В этом случае компилятор делает два предположения: любой указатель, полученный из значения, не типизированного по указателю, не является псевдонимом какого-либо указателя, полученного по Mojo, и что любые вызовы внешних функций оказывают произвольное влияние на память.await
теперь его использует сопрограмма on. Это подтверждает неизменность того, что сопрограммы можно ожидать только один раз.Изменения в стандартной библиотеке
builtin
пакет:
- Набор автоматически импортируемых объектов (типов, псевдонимов, функций) в пользовательские программы Mojo был значительно сокращен. Раньше, при обработке модуля
builtin
, все объекты в следующих модулях включались автоматически:memory
,sys
,os
,utils
,python
,bit
,random
,math
,builtin
,collections
Теперь в пользовательские программы Mojo автоматически импортируются только явно перечисленные объекты вprelude/__init__.mojo
. Это приведет к поломке большого количества пользовательского кода, поскольку пользователям нужно будет явно импортировать то, что они используют, для случаев, которые ранее обычно включались ранее (таких какOptional
,Variant
, и функций, таких какabort()
,alignof()
,bitcast()
,bitwidthof()
external_call()
,simdwidthof()
sizeof()
,,,,,,,,,,,,,,,,,,, и,,,).- Некоторые типы из модуля
builtin
были перемещены в другие модули для большей ясности, что стало возможным благодаря наличию модуляprelude
, который может повторно экспортировать символы из модулей, отличных отbuiltin
.В частности,builtin.string
модуль был перенесен вcollections.string
.- Ввод и вывод:
- Добавлена встроенная функция
input()
, которая работает так же, как Python. (PR #3392)name =input("Enter your name: ") print("Hello, "+ name +"!")
Если пользователь введёт «Mojo», он получит ответ «Привет, Mojo!»
При запуске функции
input()
с JIT-компиляцией возникает известная проблема (см. проблему #3479).print()
Теперь требуется, чтобы аргументы соответствовали признакуFormattable
. Это позволяет по умолчанию выполнять эффективную потоковую запись, избегая ненужного выделения промежуточных строк в памяти.Ранееprint()
требуемые типы соответствовалиStringable
. Это означало, что для выполнения вызова типаprint(a, b, c)
были отключены по крайней мере три отдельных выделения кучи строк для хранения отформатированных значенийa
,b
иc
соответственно. Общее количество распределений могло бы быть намного выше, если бы, например,a.__str__()
было реализовано объединение полейa
, как в следующем примере:structPoint(Stringable): var x: Float64 var y: Float64 fn__str__(self)-> String: # Performs 3 allocations: 1 each for str(..) of each of the fields, # and then the final returned `String` allocation. return"("+str(self.x)+", "+str(self.y)+")"
Тип, подобный приведенному выше, может перейти к дополнительной реализации
Formattable
со следующими изменениями:structPoint(Stringable, Formattable): var x: Float64 var y: Float64 fn__str__(self)-> String: return String.format_sequence(self) fnformat_to(self,inout writer: Formatter): writer.write("(",self.x,", ",self.y,")")
В приведенном выше примере,
String.format_sequence()
используется для созданияString
из типа, который реализуетFormattable
. Этот шаблон реализацииStringable
реализации типа с точки зрения егоFormattable
реализации сводит к минимуму шаблонность и дублирование кода, сохраняя обратную совместимость с требованиями часто используемойstr()
функции.Примечаниеdebug_assert()
теперь также требуется, чтобы егоmessage
аргумент соответствовалFormattable
.- Добавлено
TemporaryDirectory
в модулеtempfile
. (PR 2743)- Добавлено
NamedTemporaryFile
в модулеtempfile
. (PR 2762)String
и друзья:
builtin.string
Модуль был перемещен вcollections.string
.- Добавлен
String.format()
метод. (PR #2771)Поддерживает автоматическую и ручную индексацию*args
.Примеры:print( String("{1} Welcome to {0} {1}").format("mojo","") ) # Wecome to mojo
print(String("{} {} {}").format(True,1.125,2)) #True 1.125 2
String.format()
теперь поддерживаются флаги преобразования!s
и!r
, позволяющие выполнятьstr()
иrepr()
преобразования в строках формата. (PR #3279)Пример:String("{} {!r}").format("Mojo","Mojo") # "Mojo 'Mojo'" String("{0!s} {0!r}").format("Mojo") # "Mojo 'Mojo'"
- Класс
String
теперь имеет методыrjust()
,ljust()
, иcenter()
для возврата строки с выравниванием по ширине и по символу заполнения. (PR #3278)- Функция
atol()
теперь корректно поддерживает ведущие подчёркивания (например,atol("0x_ff", 0)
), когда указана или выводится соответствующая база (основание 0). Целочисленные литералы, отличные от десятичной системы счисления, в соответствии с Целочисленными литералами Python. (PR #3180)- Добавлен метод
unsafe_cstr_ptr()
дляString
иStringLiteral
, который возвращаетUnsafePointer[C_char]
для удобной совместимости с API-интерфейсами C.- Добавлен метод
byte_length()
вString
,StringSlice
, иStringLiteral
и удалены их частные методы_byte_length()
. Добавлен комментарий к методуString.__len__()
, что в будущем он будет возвращать длину в кодовых точках Юникода, иStringSlice.__len__()
теперь возвращает длину в кодовых точках Юникода. (PR #2960)- Добавлен новый псевдоним типа
StaticString
. Его можно использовать вместоStringLiteral
для строковых аргументов во время выполнения.- Добавлен
StringSlice
инициализатор, который принимаетStringLiteral
.- Конструкторы
StringRef
изDTypePointer.int8
были изменены таким образом, чтобы приниматьUnsafePointer[C_char]
в качестве параметра, что отражает их использование для совместимости с API-интерфейсами C.- Продолжен переход к
UnsafePointer
и типу беззнаковых байтов для строк:
String.unsafe_ptr()
теперь возвращаетUnsafePointer[UInt8]
(былоUnsafePointer[Int8]
)StringLiteral.unsafe_ptr()
теперь возвращаетUnsafePointer[UInt8]
(былоUnsafePointer[Int8]
)UnsafePointer
и другие изменения ссылочного типа:
DTypePointer
,LegacyPointer
иPointer
были удалены. Вместо них используйтеUnsafePointer
. Дополнительную информацию об использовании указателей см. в разделе Небезопасные указатели в руководстве Mojo.Функции, которые раньше принималиDTypePointer
теперь принимают эквивалентUnsafePointer
. Краткое правило для преобразованияDTypePointer
вUnsafePointer
:DTypePointer[type]-> UnsafePointer[Scalar[type]]
Могут быть места, где у вас есть код формы:
fnf(ptr: DTypePointer):
что эквивалентно
DTypePointer[*_]
. В этом случае вам нужно будет добавить параметрtype
только для вывода:fn f[type: DType,//](ptr: UnsafePointer[Scalar[type]]):
потому что мы не можем иметь несвязанный параметр внутри структуры.
Также могут быть места, где вы используете
DTypePointer[Scalar[DType.invalid/index]]
, и было бы логично заменить их наUnsafePointer[NoneType/Int]
. Но поскольку это неUnsafePointer
для храненияScalar
, вам, возможно, придётсяrebind/bitcast
для соответствующих типов.- Методы
DTypePointer
load()
иstore()
были перенесены вUnsafePointer
.UnsafePointer
теперь поддерживаютсяstrided_load()
,strided_store()
,gather()
, иscatter()
когда базовым типом являетсяScalar[DType]
.- Глобальные функции для работы с
UnsafePointer
стали методами благодаря использованию условных соответствий:
destroy_pointee(p)
=>p.destroy_pointee()
move_from_pointee(p)
=>p.take_pointee()
initialize_pointee_move(p, value)
=>p.init_pointee_move(value)
initialize_pointee_copy(p, value)
=>p.init_pointee_copy(value)
move_pointee(src=p1, dst=p2)
=>p.move_pointee_into(p2)
- Метод
UnsafePointer.offset()
устарел и будет удалён в следующей версии. Вместо него используйте арифметику указателей.new_ptr = ptr.offset(1)
Становится:
new_ptr = ptr +1
UnsafePointer
теперь естьalignment
параметр для указания статического выравнивания указателя. Следовательно,UnsafePointer.alloc()
больше не принимает параметр выравнивания, и выравнивание должно быть указано в типе.UnsafePointer[type].alloc[alignment](x)# now becomes UnsafePointer[type, alignment].alloc(x)
UnsafePointer
появился новыйexclusive: Bool = False
параметр. Если для этого параметра установлено значение true, компилятор понимает, что пользователь знает, что этот указатель и все производные от него указатели имеют исключительный доступ к базовому выделению памяти. Компилятор не гарантирует, что будет что-то делать с этой информацией.- Больше нельзя преобразовывать (неявно или явно) из
Reference
вUnsafePointer
. ВместоUnsafePointer(someRef)
используйтеUnsafePointer.address_of(someRef[])
для явного указания в коде, чтоUnsafePointer
получает адрес того, на что указывает ссылка.- Изменения в совместимости Python:
- Mojo теперь поддерживает совместимость с Python 3.12.
- Теперь можно создать вложенный
PythonObject
из списка или кортежа объектов Python:var np = Python.import_module("numpy") var a = np.array([1,2,3]) var b = np.array([4,5,6]) var arrays = PythonObject([a, b]) assert_equal(len(arrays),2)
Также позволяет использовать более удобный синтаксис вызова:
var stacked = np.hstack((a, b)) assert_equal(str(stacked),"[1 2 3 4 5 6]")
- Доступ к локальным модулям Python с помощью
Python.add_to_path(".")
больше не требуется. Теперь он ведет себя так же, как Python. Вы можете получить доступ к модулям в той же папке, что и целевой файл.:
mojo run /tmp/main.mojo
можно получить доступ/tmp/mymodule.py
mojo build main.mojo -o ~/myexe && ~/myexe
можно получить доступ~/mymodule.py
- Коллекции:
List
значения теперь сопоставимы по равенству с==
и!=
, когда их тип элемента сопоставим по равенству. (PR # 3195)Optional
значения теперь сопоставимы по равенству с==
и!=
, когда их тип элемента сопоставим по равенству.- Добавлен новый
Counter
словарный тип, соответствующий большинству функций Python one. (PR # 2910)Dict
теперь реализуетsetdefault()
функцию, которая получает значение из словаря по ключу или устанавливает значение по умолчанию, если его нет. (PR #2803)Dict
теперь поддерживаетpopitem()
, который удаляет и возвращает последний элемент вDict
. (PR #2701)- Добавлена
Dict.__init__()
перегрузка для указания начальной ёмкости. (PR #3171)Ёмкость должна быть степенью двойки и больше или равна 8.Это позволяет ускорить инициализацию, пропуская этапы постепенного роста.Пример:
var dictionary = Dict[Int,Int](power_of_two_initial_capacity =1024) # Insert (2/3 of 1024) entries
ListLiteral
теперь поддерживает__contains__()
. (PR #3251)- Утилиты файловой системы и среды:
Path.home()
был добавлен для возврата пути к домашнему каталогу пользователя.os.path.expanduser()
иpathlib.Path.exapanduser()
были добавлены для того, чтобы можно было расширить~
с префиксом вString
илиPath
с помощью домашнего пути пользователя:import os print(os.path.expanduser("~/.modular")) # /Users/username/.modular print(os.path.expanduser("~root/folder")) # /var/root/folder (on macos) # /root/folder (on linux)
os.path.split()
добавлено для разделения пути наhead, tail
:import os head, tail = os.path.split("/this/is/head/tail") print("head:", head) print("tail:", tail) # head: /this/is/head # tail: tail
os.makedirs()
иos.removedirs()
добавлены для создания и удаления вложенных каталогов:import os path = os.path.join("dir1","dir2","dir3") os.path.makedirs(path, exist_ok=True) os.path.removedirs(path)
- Модуль
pwd
был добавлен для доступа к пользовательской информации в/etc/passwd
в системах POSIX. Он работает по той же логике, что и Python:import pwd import os current_user = pwd.getpwuid(os.getuid()) print(current_user) # pwd.struct_passwd(pw_name='jack', pw_passwd='********', pw_uid=501, # pw_gid=20, pw_gecos='Jack Clayton', pw_dir='/Users/jack', # pw_shell='/bin/zsh') print(current_user.pw_uid) # 501 root = pwd.getpwnam("root") print(root) # pwd.struct_passwd(pw_name='root', pw_passwd='*', pw_uid=0, pw_gid=0, # pw_gecos='System Administrator', pw_dir='/var/root', pw_shell='/bin/zsh')
- Другие новые возможности и сопутствующие функции:
- Добавлена черта
ExplicitlyCopyable
для обозначения типов, которые можно копировать явно, но которые могут не поддерживаться неявным копированием.Это поддерживает работу по отказу от неявной копируемости типов коллекций стандартной библиотеки, которая может привести к непреднамеренным дорогостоящим копиям.- Добавлен
Identifiable
признак, используемый для описания типов, реализующих методы__is__()
и__isnot__()
trait. (PR #2807)- Типы, соответствующие
Boolable
(то есть реализующие__bool__()
), больше не преобразуются неявно вBool
. Для типов, в которых требуется такое поведение, вводится новая чертаImplicitlyBoolable
.- Разное:
NoneType
Теперь это обычный тип стандартной библиотеки, а не псевдоним для необработанного типа MLIR.Подписи функций, написанные какfn() -> NoneType
, должны перейти к записи какfn() -> None
.- Теперь у Mojo есть
UInt
тип для моделирования целых чисел без знака (скалярных) с шириной, зависящей от платформы.UInt
реализует большинство арифметических операций, которые имеют смысл для целых чисел, за заметным исключением__neg__()
. Встроенные функции, такие какmin()
/max()
, а такжеmath
функции, такие какceildiv()
,align_down()
, иalign_up()
также реализованы дляUInt
.- Теперь, когда у нас есть
UInt
тип, используйте его для представления возвращаемого типа хэша. В общем случае хэши должны быть целыми числами без знака, а также могут привести к повышению производительности в определенных случаях.- Добавлен
C_char
псевдоним типа вsys.ffi
.sort()
теперь поддерживаетсяstable
параметр. Его можно вызвать с помощьюsort[cmp_fn, stable=True](list)
Для работы алгоритма требуется ()O(N) вспомогательной памяти. При выделении дополнительной памяти происходит сбой, программа завершает работу.
sort()
больше не выполняетсяLegacyPointer
, поскольку этот тип теперь удален.- Добавлена
oct()
встроенная функция для форматирования целых чисел в восьмеричном формате. (PR # 2914)- Добавлены функции
assert_is()
иassert_is_not()
тестирования вtesting
модуль.- В
math
пакет теперь входят константыpi
,e
иtau
(закрывает выпуск #2135).ulp
Функция изnumerics
была перенесена вmath
модуль.bit
модуль теперь поддерживаетbit_reverse()
,byte_swap()
иpop_count()
дляInt
типа. (PR # 3150)- Несколько
bit
функций были переименованы для большей ясности:
countl_zero()
->count_leading_zeros()
countr_zero()
->count_trailing_zeros()
Slice
теперь используетOptionalReg[Int]
дляstart
иend
и реализует конструктор, который принимает необязательные значения.Slice._has_end()
также был удалён, поскольку срез без конца теперь представлен пустым вариантомSlice.end
(PR #2495)var s = Slice(1,None,2) print(s.start.value())# must retrieve the value from the optional
- Аргумент
rank
дляalgorithm.elementwise()
больше не требуется и выводится только по умолчанию.time.now()
Функция устарела. Пожалуйста, используйтеtime.perf_counter()
илиtime.perf_counter_ns
вместо этого.SIMD
построение изBool
было ограниченоDType.bool
типом данных.Изменения в инструменте
mojo test
новые функции и изменения:
mojo test
Теперь для запуска модульных тестов используется компилятор Mojo. Это позволит устранить проблемы с компиляцией, которые иногда возникали, а также сократит общее время тестирования, поскольку мы будем компилировать модульные тесты только один раз перед их выполнением.Эти изменения не распространяются на doctests из-за их иной семантики.mojo test
Команда теперь принимает--filter
параметр, который сузит набор собираемых и выполняемых тестов. Строка фильтра представляет собой расширенное регулярное выражение POSIX.- Команда
mojo test
теперь поддерживает использование тех же параметров компиляции, что иmojo build
.- Теперь вы можете отлаживать модульные тесты с помощью
mojo test
, передав--debug
флаг. Поддерживаются большинство флагов отладки; запуститеmojo test --help
для получения полного списка.Отладка doctests в настоящее время не поддерживается.- Новые функции и изменения Mojo debugger:
mojo debug --rpc
Команда была переименована вmojo debug --vscode
, которая теперь может управлять несколькими окнами VS Code.- Отладчик Mojo теперь поддерживает
break-on-raise
команду, которая указывает отладчику останавливаться при выполнении любыхraise
инструкций. Аналогичные функции были добавлены в отладчик в VS Code.- Отладчик Mojo теперь скрывает аргументы искусственной функции
__result__
и__error__
, созданные компилятором для кода Mojo.- Изменения в поддержке VS Code:
- Расширение VS Code теперь поддерживает пакет MAX SDK для VS Code, который автоматически загружается расширением и используется для всех функций Mojo, включая сервер Mojo Language Server, Mojo debugger, Mojo formatter и многое другое.
- На сервер Mojo Language в VS Code добавлен прокси, который более корректно обрабатывает сбои.
- Сервер Mojo Language Server больше не устанавливает
.
в качестве символа фиксации для автозаполнения.❌ Удалено
- Поддержка устаревшей
fn __init__(...) -> Self:
формы была удалена из компилятора, пожалуйста, переключитесь на использованиеfn __init__(inout self, ...):
вместо этого.- Встроенный
tensor
модуль удален. Идентичная функциональность доступна вmax.tensor
, но обычно рекомендуется использовать структуры изbuffer
модуля, когда это возможно.- Удалено
String.unsafe_uint8_ptr()
.String.unsafe_ptr()
теперь возвращает то же самое.- Удалено
StringLiteral.unsafe_uint8_ptr()
иStringLiteral.as_uint8_ptr()
.- Удалено
SIMD.splat(value: Scalar[type])
. Вместо этого используйте конструктор дляSIMD
.- Удалены
SIMD.{add,mul,sub}_with_overflow()
методы.- Удалены методы
SIMD.min()
иSIMD.max()
. Идентичная функциональность доступна с помощью встроенных функцийmin()
иmax()
.- Удалены предупреждения сервера Mojo Language о неиспользуемых аргументах функции.
Run Mojo File in Dedicated Terminal
действие удалено, и оноRun Mojo File
всегда будет открывать специальный терминал для каждого файла mojo, чтобы гарантировать правильную среду.️ Исправлено
- Исправлен сбой на языковом сервере Mojo при импорте текущего файла.
- Исправлен сбой при указании аргументов ключевого слова variadic без выражения типа в
def
функциях, например:deffoo(**kwargs):...# now works
- Mojo теперь печатает
ref
аргументы и результаты в сгенерированной документации корректно.- # 1734 - Вызов
__copyinit__
self вызывает сбой.- # 3142 - [QoI] Сбивающий с толку
__setitem__
метод завершается ошибкой «должен быть изменяемым».- # 248 - [Функция] Позволяет
__setitem__
принимать переменные аргументы- # 3065 - Исправлено некорректное поведение
SIMD.__int__
для неподписанных типов- # 3045 - Отключить неявные маршруты преобразования SIMD с помощью
Bool
- # 3126 - Список [ОШИБОК] не работает во время компиляции.
- #3237 - [ОШИБКА] Разница между
__getitem__
и[.]
оператором.- # 3336 - Исправлены устаревшие ссылки на
let
в документации REPL.- Расширение VS Code больше не кэширует информацию о выбранном MAX SDK, что вызывало проблемы при внесении изменений в SDK.
- Отладчик Mojo теперь перестает показывать ложные предупреждения при анализе замыканий.
Версия от 7-го июня 2024-го года:
версия 24.4 (2024-06-07)
✨ Основные моменты
Важные темы для этого выпуска:
- Улучшена производительность и простота использования
def
функций.- Продолжена унификация стандартных библиотечных API вокруг
UnsafePointer
типа.- Множество улучшений качества жизни для стандартных типов библиотечных коллекций.
- Значительные улучшения производительности при вставке в
Dict
. Производительность по этому показателю всё ещё не такая, какой мы хотели бы её видеть, но она значительно улучшена.- Новый
@parameter for
механизм для выражения циклов времени компиляции, который заменяет более ранний (и менее надёжный)@unroll
декоратор.- Новые страницы руководства Mojo по потоку управления, тестированию и использованию небезопасных указателей.
На странице, адрес которой приведен чуть ниже, вверху правой колонки можно посмотреть номер новой версии Mojo и дату её публикации, а в основном тексте перечислены особенности новой версии.
Привожу информацию со страницы https://docs.modular.com/mojo/changelog :
- Проект
- Журнал изменений
Журнал изменений Mojo
Это текущий список существенных изменений языка и инструментов Mojo. Он не включает все внутренние изменения реализации.
Обновите Моджо
Если у Вас ещё нет Mojo, см. руководство по началу работы .
Чтобы увидеть свою версию Mojo, запустите это:
mojo --version
modular update mojo
v24.3 (02.05.2024 )
✨ Основные моменты
AnyPointer
был переименован вUnsafePointer
и теперь является предпочтительным типом небезопасного указателя Mojo. Он имеет несколько улучшений, в том числе:
- Тип элемента теперь может быть любым: для этого не требуется
Movable
.- По этой причине
take_value()
методыemplace_value()
, иmove_into()
были заменены на функции верхнего уровня и переименованы. Новые функции:- Новая
destroy_pointee()
функция запускает деструктор указателя.UnsafePointer
может быть инициализирован непосредственно изReference
withUnsafePointer(someRef)
и преобразован в ссылку с помощьюyourPointer[]
. Оба выводят тип элемента и адресное пространство. Обратите внимание: когда вы преобразуете указатель в ссылку, Mojo не может отслеживать время жизни исходного значения. Таким образом, полученная ссылка не безопаснее исходного указателя.- Все типы указателей подверглись некоторой очистке, чтобы сделать их более согласованными, например,
unsafe.bitcast()
глобальная функция теперь является согласованнымbitcast()
методом для указателей, который может преобразовывать тип элемента и адресное пространство.- Улучшения в поддержке переменных аргументов.
- Аргументы гетерогенного пакета с вариациями теперь надежно работают даже с типами памяти и имеют более удобный для использования API, определенный типом
VariadicPack
. Например, упрощенную версиюfnprint[T: Stringable,*Ts: Stringable](first: T,*rest:*Ts): print_string(str(first)) @parameter fn print_elt[T: Stringable](a: T): print_string(" ") print_string(a) rest.each[print_elt]()
- Mojo теперь поддерживает объявление функций, которые имеют как необязательные, так и переменные аргументы, как позиционные, так и только ключевые слова. Например, теперь это работает:
fnvariadic_arg_after_default( a: Int, b: Int =3,*args: Int, c: Int, d: Int =1,**kwargs: Int ):...
Позиционные вариационные параметры также работают при наличии необязательных параметров. То есть:
fn variadic_param_after_default[e: Int, f: Int =2,*params: Int](): pass
Обратите внимание, что параметры ключевого слова с переменным числом вариантов пока не поддерживаются.
Для получения дополнительной информации см. аргументы Variadic в Руководстве Mojo.
- Команды
mojo build
иmojo run
теперь поддерживают-g
опцию. Этот более короткий псевдоним эквивалентен написанию--debug-level full
. Эта опция также доступна вmojo debug
команде, но уже используется по умолчанию.- Было добавлено множество новых API стандартных библиотек, в том числе множество вкладов сообщества. Изменения перечислены в разделе стандартной библиотеки.
- В Руководстве Mojo появилась новая страница «Типы» .
Языковые изменения
- Некоторые методы dunder, которые принимают индексы (
__getitem__()
,__setitem__()
и__refitem__()
) или имена (__getattr__()
и__setattr__()
), теперь могут принимать индекс или имя в качестве значения параметра, а не значения аргумента. Это становится возможным, когда вы определяете один из этих методов без каких-либо аргументов, кромеself
(для метода получения) илиself
заданного значения (для метода установки).Это позволяет использовать типы, индексация которых может осуществляться только с помощью параметров, а также такие вещи, как следующий пример, в котором имя атрибута передается в качестве параметра, чтобы имена атрибутов можно было проверить во время компиляции.structRGB: fn __getattr__[name: StringLiteral](self)-> Int: @parameter if name =="r":return... elif name =="g":return... else: constrained[name =="b","can only access with r, g, or b members"]() return... var rgb = RGB() print(rgb.b)# Works print(rgb.q)# Compile error
- Mojo теперь позволяет пользователям фиксировать расположение исходного кода и динамически вызывать расположение функций с помощью встроенных функций
__source_location()
и__call_location()
. Например:@always_inline fnmy_assert(cond: Bool, msg: String): ifnot cond: var call_loc = __call_location() print("In", call_loc.file_name,"on line",str(call_loc.line)+":", msg) fnmain(): my_assert(False,"always fails")# some_file.mojo, line 193
Это печатает »
In /path/to/some_file.mojo on line 193: always fails
«. Обратите внимание, что__call_location()
работает только в функциях@always_inline
или@always_inline("nodebug")
. Он дает неправильные результаты, если его поместить в@always_inline
функцию, вызываемую из функции@always_inline("nodebug")
.Ни один из
__source_location()
них не__call_location()
работает при вызове в контексте параметра. Например:@always_inline fnmystery_location()-> String: var loc = __call_location() returnstr(loc.file_name) defmain(): alias doesnt_work = mystery_location()# <unknown location in parameter context>
Изменения в стандартной библиотеке
⭐️ Новинка
List
имеет несколько новых методов:
pop(index)
для удаления элемента по определенному индексу. По умолчаниюList.pop()
удаляет последний элемент в списке. ( @LJ-9801 , исправления #2017 )resize(new_size)
для изменения размера списка без необходимости указания дополнительного значения. ( @mikowals , исправления #2133 )insert(index, value)
для вставки значения по указанному индексу в файлList
. ( @whym1here , исправления #2134 )- Новый конструктор
List(ptr, size, capacity)
, позволяющий избежать необходимости делать глубокую копию существующего непрерывного выделения памяти при создании нового файлаList
. ( @StandinKP , исправления #2170 )Dict
теперь естьupdate()
метод обновления ключей/значений из другого файлаDict
. ( @gabrieldemarmiesse )Set
теперь имеет именованные методы для операций над множествами:
difference()
сопоставление с-
difference_update()
сопоставление с-=
intersection_update()
сопоставление с&=
update()
сопоставление с|=
( @arvindavoudi )
Dict
,List
, иSet
все соответствуютBoolable
признаку. Коллекции оцениваются,True
содержат ли они какие-либо элементы,False
в противном случае:deflist_names(names: List[String]): if names: for name in names: print(name[]) else: print("No names to list.")
- Добавлена
reversed()
функция создания обратных итераторов. Несколько типов диапазонов,List
, иDict
теперь поддерживают обратную итерацию.var numbers = List(1,2,3,4,5) for number inreversed(numbers): print(number)
( @helehex и @jayzhan211 , внесли свой вклад в #2325 )
Optional
теперь реализует__is__
и__isnot__
методы, чтобы вы могли сравнить ихOptional
сNone
. Например:var opt = Optional(1) if opt isnotNone: print(opt.value()[])
Tuple
теперь работает с типами элементов, занимающими только память, например,String
и позволяет напрямую индексировать их с помощью выражения параметра. Это означает, что теперь вы можете просто использоватьx = tup[1]
Python вместоx = tup.get[1, Int]()
. Теперь вы также можете назначать элементы кортежа с помощьюtup[1] = x
.vartuple=("Green",9.3) var name =tuple[0] var value =tuple[1]
Обратите внимание: поскольку нижний индекс должен быть выражением параметра, вы не можете выполнять итерацию с
Tuple
помощью обычногоfor
цикла.- Тип
Reference
претерпел несколько изменений, в том числе:
- Он переехал в
memory.reference
модуль вместоmemory.unsafe
.Reference
теперь имеетunsafe_bitcast()
метод, аналогичный типам указателей.- Было удалено несколько небезопасных методов, в том числе
offset()
,destroy_element_unsafe()
иemplace_ref_unsafe()
. Это потому, чтоReference
это безопасный тип — используйте егоUnsafePointer
для выполнения небезопасных операций.Bool
теперь может быть неявно преобразован из любого типа, соответствующегоBoolable
признаку. Это означает, что вам больше не нужно писать такой код:@value structMyBoolable: fn__bool__(self)-> Bool:... fn takes_boolable[T: Boolable](cond: T):... takes_boolable(MyBoolable())
Вместо этого вы можете просто написать:
fntakes_bool(cond: Bool):... takes_bool(MyBoolable())
Обратите внимание, что вызовы
takes_bool()
будут выполнять неявное преобразование, поэтому в некоторых случаях все же лучше явно объявить параметр типа, например:fn takes_two_boolables[T: Boolable](a: T, b: T): # Short circuit means `b.__bool__()` might not be evaluated. if a.__bool__()and b.__bool__(): ...
PythonObject
теперь соответствуетKeyElement
признаку, а это означает, что его можно использовать в качестве типа ключа дляDict
. Это позволяет вам легко создавать словари Python и взаимодействовать с ними в Mojo:defmain(): d = PythonObject(Dict[PythonObject, PythonObject]()) d["foo"]=12 d[7]="bar" d["foo"]=[1,2,"something else"] print(d)# prints `{'foo': [1, 2, 'something else'], 7: 'bar'}`
FileHandle.seek()
теперь имеетwhence
аргумент, который по умолчанию выполняетos.SEEK_SET
поиск с начала файла. Теперь вы можете установитьos.SEEK_CUR
смещение на текущуюFileHandle
позицию поиска:var f =open("/tmp/example.txt") # Skip 32 bytes f.seek(os.SEEK_CUR,32)
Или
os.SEEK_END
для смещения от конца файла:# Start from 32 bytes before the end of the file f.seek(os.SEEK_END,-32)
FileHandle.read()
теперь можно читать прямо вDTypePointer
:varfile=open("/tmp/example.txt","r") # Allocate and load 8 elements var ptr = DTypePointer[DType.float32].alloc(8) varbytes=file.read(ptr,8) print("bytes read",bytes) print(ptr.load[width=8]())
- Модуль
sys
теперь содержитexit()
функцию, которая завершает программу Mojo с указанным кодом ошибки.from sys import exit exit(0)
- Конструкторы for
Tensor
были изменены, чтобы сделать их более последовательными. В результате конструкторы принимают форму в качестве первого аргумента (а не второго) при построении тензора с данными указателя.Если вы передаете конструктору одно скалярное значениеTensor
, он теперь передает это значение всем элементам тензора. Например,Tensor[DType.float32](TensorShape(2,2), 0)
создает2x2
тензор, инициализированный всеми нулями. Это обеспечивает простой способ заполнения данных тензора.String
теперь естьremoveprefix()
иremovesuffix()
методы. ( @gabrieldemarmiesse )- Функции
ord
иchr
были улучшены и позволяют принимать любые символы Юникода. ( @mzaks , способствует #1616 )atol()
теперь обрабатывает пробелы. Функцияatol()
используется внутриString.__int__()
, поэтомуint(String( " 10 "))
теперь возвращает результат10
, а не выдает ошибку. ( @artemiogr97 )SIMD
теперь реализует__rmod__()
метод. ( @bgreni , исправления #1482 )bool(None)
сейчас реализовано. ( @zhoujingya )- Тип
DTypePointer
теперь реализуетgather()
сборSIMD
вектора по смещениям текущего указателя. Аналогичным образом была добавлена поддержкаscatter()
разбросаSIMD
вектора по смещениям текущего указателя. ( @leandrolcampos )- Функция
len()
теперь обрабатываетrange()
указанное значение с отрицательным конечным значением, поэтому такие вещиlen(range(-1))
работают правильно. ( @сорарос )debug_assert()
теперь печатает его местоположение (имя файла, строку и столбец, в котором он был вызван) в сообщении об ошибке. Аналогично,assert
помощники вtesting
модуле теперь включают в свои сообщения информацию о местоположении.- Функция
testing.assert_equal[SIMD]()
теперь вызывается, если какой-либо из элементов не совпадает в двухSIMD
сравниваемых аргументах. ( @gabrieldemarmiesse )- Функции
testing.assert_almost_equal()
иmath.isclose()
теперь имеютequal_nan
флаг. Если установлено значениеTrue
, NaN считаются равными.- Тип
object
теперь поддерживает операторы деления, по модулю, а также сдвигов влево и вправо, включая варианты на месте и в обратном направлении. ( @LJ-9801 , исправления #2224 )- Добавлены проверяемые арифметические операции для
SIMD
целых чисел.SIMD
Целочисленные типы (включая скаляры целых чисел, такие какInt64
) теперь могут выполнять проверенные сложения, вычитания и умножения, используя следующие новые методы:Проверенная арифметика позволяет вызывающей стороне определить, превысила ли операция числовые пределы типа. Например:
var simd = SIMD[DType.int8,4](7,11,13,17) var product: SIMD[DType.int8,4] var overflow: SIMD[DType.bool,4] (product, overflow)= simd.mul_with_overflow(simd) for i inrange(len(product)): if overflow[i]: print("<overflow>") else: print(product[i])
( @лш )
- Добавлен
os.remove()
иos.unlink()
для удаления файлов. ( @artemiogr97 , исправления #2306 )Изменился
- Функция
parallel_memcpy()
переехала изbuffer
пакета вalgorithm
пакет. Пожалуйста, обновите импорт соответствующим образом.Optional.value()
теперь возвращает ссылку вместо копии содержащегося значения.Чтобы выполнить копирование вручную, разыменуйте результат:var result = Optional(123) var value = result.value()[]
- В соответствии с принятым предложением сообщества « Стандартизировать представление последовательности байтов в виде последовательности 8-битных целых чисел без знака » переход к использованию начался
UInt8
с изменения указателя данныхError
наDTypePointer[DType.uint8]
. ( @gabrieldemarmiesse , вносит свой вклад в #2317 )- Продолжается переход
UnsafePointer
от устаревшегоPointer
типа в различных API и внутренних компонентах стандартной библиотеки. ( @gabrieldemarmiesse )Изменения в инструментах
- Поведение
mojo build
при вызове без выходного-o
аргумента немного изменилось:mojo build ./test-dir/program.mojo
теперь исполняемый файл выводится в путь./program
, тогда как раньше он выводился в путь./test-dir/program
.- Команда
mojo package
больше не поддерживает этот-D
флаг. Все флаги среды компиляции должны быть предоставлены в момент использования пакета (например,mojo run
илиmojo build
).- REPL больше не позволяет неинициализировать объявления переменных уровня типа, например, он будет отклонять
var s: String
. Это связано с тем, что он не обеспечивает надлежащего отслеживания времени жизни (пока!) между ячейками, и такой код может привести к сбою. Эту проблему можно обойти, инициализировав фиктивное значение и перезаписав его позже. Это ограничение применимо только к переменным верхнего уровня, переменные в функциях работают так же, как и всегда.Другие изменения
Языковые изменения
- Была добавлена встроенная функция низкого уровня,
__get_mvalue_as_litref(x)
предоставляющая доступ к базовому представлению памяти в виде!lit.ref
значения без проверки статуса инициализации базового значения. Это полезно в логике очень низкого уровня, но не предназначено для общего удобства использования и, вероятно, изменится в будущем.- Свойства теперь можно указывать во встроенных операциях MLIR:
_ =__mlir_op.`kgen.source_loc`[ _type =( __mlir_type.index,__mlir_type.index,__mlir_type.`!kgen.string` ), _properties =__mlir_attr.`{inlineCount =1: i64}`, ]()
Как показано в примере выше,
_properties
атрибут protected можно передать во время построения операции соDictionaryAttr
значением MLIR.❌ Удален
- Поддержка пакетов вариаций «только для регистрации» удалена. Вместо
AnyRegType
, пожалуйста, обновите свой код доAnyType
таких примеров:fn your_function[*Types: AnyRegType](*args:*Ts):...
Этот шаг дает вам доступ к более удобному API и имеет то преимущество, что он безопасен для памяти и корректен для нетривиальных типов. Если вам нужны конкретные API для типов, используйте правильный признак вместо
AnyType
.List.pop_back()
был удален. Вместо этого используйтеList.pop()
вариант, который по умолчанию выталкивает последний элемент в списке.SIMD.to_int(value)
был удален. Используйтеint(value)
вместо этого.- Магическая
__get_lvalue_as_address(x)
функция удалена. Чтобы получить ссылку на использование значенияReference(x)
и если вам нужен небезопасный указатель, вы можете использоватьUnsafePointer.address_of(x)
.️ Исправлено
- #516 и #1817 и многие другие, например «Невозможно создать функцию, возвращающую две строки».
- #1178 (os/kern) сбой (5).
- #1609 псевдоним с
DynamicVector[Tuple[Int]]
ошибками.- #1987 На данный момент определение
main
в пакете Mojo является ошибкой. Это пока не предназначено для работы, ошибки на данный момент помогут предотвратить случайное неопределенное поведение.- #1215 и #1949 Сервер Mojo LSP больше не отключает предварительный просмотр при наведении для функций с функциональными аргументами, параметрами или результатами.
- #1901 Исправлена обработка Mojo LSP и генерации документации для входных аргументов.
- #1913 -
0__
парсер Mojo больше не аварийно завершает работу.- #1924 Исправлена JIT-отладка на Mac.
- #1941 Вариативные аргументы Mojo не работают с нетривиальными типами, состоящими только из регистров.
- #1963
a!=0
теперь правильно анализируется и форматируется с помощьюmojo format
.- #1676 Исправлен сбой, связанный с
@value
декоратором и структурами с пустым телом.- #1917 Исправлен сбой после синтаксической ошибки во время создания кортежа.
- #2006 Mojo LSP теперь правильно поддерживает типы подписей с именованными аргументами и параметрами.
- #2007 и #1997 Mojo LSP больше не аварийно завершает работу при определенных типах замыканий.
- #1675 Обеспечить
@value
корректный сбой декоратора после ошибки дублирования поля.- #2068 Исправление
SIMD.reduce()
размера _out == 2. ( @soraros ).
…
!…
Приглашаю всех высказываться в Комментариях. Критику и обмен опытом одобряю и приветствую. В особо хороших комментариях сохраняю ссылку на сайт автора!
И не забывайте, пожалуйста, нажимать на кнопки социальных сетей, которые расположены под текстом каждой страницы сайта.
Продолжение тут…