#prog #csharp #article
Тут вот на Хабре недавно была статья про тестовое задание, суть которого сводилось к тому, чтобы распарсить расписание в cron-подобном формате и потом иметь возможность делать к нему запросы на ближайший описываемый расписанием момент времени относительно заданного аргумента, причём как в будущее, так и в прошлое.Аффтар Автор негодовал из-за того, что он это тестовое задание выполнил, но его решение завернули без внятного фидбека, поэтому он выложил свой вариант на всеобщее обозрение. Зрелище, мягко говоря, не для слабонервных: практически нулевая декомпозиция, куча сложной логики с копипастой и if-ы с семикратной (!) вложенностью. Вдобавок, автор почему-то оптимизировал парсинг, а не получение моментов времени.
Сама задачка, однако, всё же застряла у меня в голове, и у меня были идеи, как можно красиво сделать как минимум парсинг формата расписания. К сожалению, у меня так и не дошли руки до написания кода. А вот у PsyHaste, известного в телеге, как @Psilon — дошли. Используя тот же язык, что и у автора оригинальной статьи — C# — он написал своё решение, смонатками монадками и, внезапно, обоснованным goto (который, впрочем, потребовался исключительно в силу отсутствия в C# оператора continue по метке). Вышло на редкость понятно и читаемо. Об этом он написал свою статью, которую я вас и приглашаю прочитать — и не только в силу технических решений, но и потому, что у Алекса довольно приятный слог.
(тут должна быть рекомендация блога Алекса, но его нету)
Тут вот на Хабре недавно была статья про тестовое задание, суть которого сводилось к тому, чтобы распарсить расписание в cron-подобном формате и потом иметь возможность делать к нему запросы на ближайший описываемый расписанием момент времени относительно заданного аргумента, причём как в будущее, так и в прошлое.
Сама задачка, однако, всё же застряла у меня в голове, и у меня были идеи, как можно красиво сделать как минимум парсинг формата расписания. К сожалению, у меня так и не дошли руки до написания кода. А вот у PsyHaste, известного в телеге, как @Psilon — дошли. Используя тот же язык, что и у автора оригинальной статьи — C# — он написал своё решение, с
(тут должна быть рекомендация блога Алекса, но его нету)
#prog #rust #csharp #article
A comparison of Rust’s borrow checker to the one in C#
В C# есть явно ссылочные аргументы функций, переменные и поля, которые объявляются с префиксом
Для того, чтобы не допустить подобного, в C# есть свой статический анализатор. В данной статье автор сравнивает этот анализатор с borrow checker из Rust и разбирает, в чём этот анализатор слабее (и в чём неожиданно сильнее).
Лично мне напомнило немного про Oxidizing Ocaml, но в C# способов управления ссылками поменьше.
A comparison of Rust’s borrow checker to the one in C#
В C# есть явно ссылочные аргументы функций, переменные и поля, которые объявляются с префиксом
ref. Помимо всего прочего, это позволяет передавать ссылки на размещённые на стеке данные. Разумеется, при отсутствии каких-либо проверок это небезопасно и позволяет получить висячую ссылку.Для того, чтобы не допустить подобного, в C# есть свой статический анализатор. В данной статье автор сравнивает этот анализатор с borrow checker из Rust и разбирает, в чём этот анализатор слабее (и в чём неожиданно сильнее).
Лично мне напомнило немного про Oxidizing Ocaml, но в C# способов управления ссылками поменьше.
👍4🌚2
Статья называется Modern C# Techniques, Part 2: Value Records, если что
(#prog #csharp #suckassstory)
(#prog #csharp #suckassstory)
🤨6🤡4😁1
#prog #csharp #article
Performance Improvements in .NET 10
Сентябрьская статья об оптимизациях в .NET. Как пишет автор, ускорение кода, как правило, достигается не за счёт одного большого изменения, а за счёт множества маленьких — и весь текст статьи это прекрасно иллюстрирует.
В статье множество примеров того, как одно изменение в JIT позволяет применить другие, уже имеющиеся оптимизации, чтобы достичь улучшения, недоступного при применении оптимизаций по отдельности.
Вместе с тем статья несколько расстраивает тем, что ясно показывает, какие усилия приходится тратить разработчикам JIT, чтобы ускорить C#. Многие эти оптимизации были бы избыточны, если бы язык был бы более выразительным или если бы использовались более высокоуровневые (и удобные!) API. Думаю, напишу как-то об этом.
Performance Improvements in .NET 10
Сентябрьская статья об оптимизациях в .NET. Как пишет автор, ускорение кода, как правило, достигается не за счёт одного большого изменения, а за счёт множества маленьких — и весь текст статьи это прекрасно иллюстрирует.
В статье множество примеров того, как одно изменение в JIT позволяет применить другие, уже имеющиеся оптимизации, чтобы достичь улучшения, недоступного при применении оптимизаций по отдельности.
Вместе с тем статья несколько расстраивает тем, что ясно показывает, какие усилия приходится тратить разработчикам JIT, чтобы ускорить C#. Многие эти оптимизации были бы избыточны, если бы язык был бы более выразительным или если бы использовались более высокоуровневые (и удобные!) API. Думаю, напишу как-то об этом.
Microsoft News
Performance Improvements in .NET 10
Take a tour through hundreds of performance improvements in .NET 10.
😢17👍3😁1🤔1
#prog #csharp #suckassstory
C# — пример того, как не надо делать язык программирования.
C# очень странно относится к затенению переменных. Обычно он это запрещает. Вот такой код, например, не компилируется:
Вывод компилятора:
Тут в if-блоке вводится новая переменная, которая перекрывает переменную выше. Однако компилятор C# (и это поведение описано в спецификации) смотрит только на включение имён в областях видимости, но не на то, когда они объявлены! Если переставить два оператора местами, код всё равно не компилируется:
Также нельзя написать код, который перекрывает параметр метода:
Однако можно написать метод, который затеняет... Поля класса! Причём и локальными переменными, и аргументами:
...но только до тех пор, пока поля класса не упоминаются в области видимости. Если упоминаются, то нельзя переиспользовать их имена:
...но можно во вложенных областях видимости:
Какой простой, консистентный и полезный набор правил!
BTW раньше было ещё хуже.
C# — пример того, как не надо делать язык программирования.
C# очень странно относится к затенению переменных. Обычно он это запрещает. Вот такой код, например, не компилируется:
string x = "Hi";
if (true) {
string x = "Bye";
}
Вывод компилятора:
error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameterТут в if-блоке вводится новая переменная, которая перекрывает переменную выше. Однако компилятор C# (и это поведение описано в спецификации) смотрит только на включение имён в областях видимости, но не на то, когда они объявлены! Если переставить два оператора местами, код всё равно не компилируется:
if (true) {
string x = "Bye";
}
string x = "Hi";Также нельзя написать код, который перекрывает параметр метода:
void method(int x) {
int x = 10; // Ошибка
}Однако можно написать метод, который затеняет... Поля класса! Причём и локальными переменными, и аргументами:
class C {
int x;
int y;
void m(int y /* ок */) {
int x = 10; // тоже ок
}
}...но только до тех пор, пока поля класса не упоминаются в области видимости. Если упоминаются, то нельзя переиспользовать их имена:
using System;
class C {
int x;
void m() {
Console.WriteLine(x);
int x = 10; // Ошибка
}
}
...но можно во вложенных областях видимости:
using System;
class C {
int x;
void m() {
Console.WriteLine(x);
{
int x = 10; // ок
}
}
}
Какой простой, консистентный и полезный набор правил!
BTW раньше было ещё хуже.
💯15😁7💩3
Блог*
#prog #csharp #suckassstory C# — пример того, как не надо делать язык программирования. C# очень странно относится к затенению переменных. Обычно он это запрещает. Вот такой код, например, не компилируется: string x = "Hi"; if (true) { string x = "Bye";…
#prog #csharp #suckassstory
Блин, спасибо, очень полезно.
Для сравнения, #java:
using System;
using System.Collections.Generic;
var arr = new int[] {1, 2, 3};
Console.WriteLine(arr); // System.Int32[]
var list = new List<int>{1, 2, 3};
Console.WriteLine(list); // System.Collections.Generic.List`1[System.Int32]
Блин, спасибо, очень полезно.
Для сравнения, #java:
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
class Main {
public static void main() {
var arr = new int[] {1, 2, 3};
System.out.println(arr); // [I@251a69d7
System.out.println(Arrays.toString(arr)); // [1, 2, 3]
var list = new ArrayList<>(List.of(1, 2, 3));
System.out.println(list); // [1, 2, 3]
}
}
😁5🍌5