LINUX.ORG.RU
ФорумTalks

Выразительный код без программазма на вашем любимом ЯП

 ,


1

2

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

На Джулии это довольно прямолинейно выражается следующим образом:

function makesequencer(next_f)
    let X = Nothing
        function(Y)
            if X == Nothing
                # initialization
                X = Y
            else
                Xnew = next_f(X, Y)
                X = Xnew
            end
            return X
        end
    end
end

А можно ли ту же идею реализовать на вашем любимом ЯП? Желательно с минимумом программазма в виде новых типов, классов-хренассов... В моем примере вообще нет упоминания никаких типов данных.

★★★★★

Ответ на: комментарий от t184256

можно ли ту же идею реализовать на вашем любимом ЯП?

Я не отклоняюсь от темы топика.

Bioreactor ★★★★★
()
Ответ на: комментарий от crutch_master

Умничать будете на собеседовании.

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

Про собеседования ...

Я ведь предсказывал -

Невезет с работой? (комментарий)

Bioreactor ★★★★★
()
Ответ на: комментарий от TheAnonymous

Это понятный код
final int[] cnt = new int[1];

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

Ссылки на что? На переменную в стеке? Это в скриптовых языках умеют делать, так называемый лексический захват, потому как там время жизни захваченных локальных переменных к стеку не привязано, в java и cях так не получится. В этом коде форсируется аллокция места в куче посредством массива, время жизни примитива в массиве начинает определять GC.

Aber ★★★★★
()
Последнее исправление: Aber (всего исправлений: 2)
Ответ на: комментарий от seiken

Уже о востребованности? До этого речь шла о «окупаемости» и «так круто платят только за Джаву».

Именно так.

Sad but true.

https://visasam.ru/russia/rabotavrf/zarplata-programmista-v-moskve.html

разбирающийся в JAVA — 120000-200000 руб.

(С)

«Разбирающийся» - это джун и мид.

Синьоры и тимлиды, естественно, зарабатывают больше.

Bioreactor ★★★★★
()
Ответ на: комментарий от Aber

Ну не знает TheAnonymous-кун, что в Java давно уже «атомики» существуют.

Причем ещё с 5-ой версии.

Кстати, про «lock-free thread-safe» в этом топике тоже вопрос был.

Bioreactor ★★★★★
()
Ответ на: комментарий от crutch_master

Ещё как выглядит!

Самый «чистый код» - это именно Java.

Недаром же https://www.labirint.ru/books/642466/ - именно на Java.

https://habr.com/ru/post/424051/

https://habr.com/ru/post/189094/

Bioreactor ★★★★★
()
Последнее исправление: Bioreactor (всего исправлений: 2)
Ответ на: комментарий от Aber

в java и cях так не получится

в чистых сях вроде вообще лямбд нет, а на крестах не надо, всё есть

#include <bits/stdc++.h>
using namespace std;
int main() {
  vector<int> v {1, 4, 8, 8};
  int sum = 0;
  for_each(v.begin(), v.end(), [&](int const & i) { sum += i; });
  cout << sum << endl;
}

TheAnonymous ★★★★★
()
Последнее исправление: TheAnonymous (всего исправлений: 1)
Ответ на: комментарий от TheAnonymous

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

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

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

std::function<void()> captureTest() {
  int sum = 100;
  auto a = [&]() {
    cout << "capture test:" << sum << endl;
    sum += 1;
  };
  // a(); // Strange behavior in clang if uncommented
  sum += 100;  
  return a;
}

void garbage(int x, int y) { // I believe that call to this function will make a mess in stack
    auto stackSpoiler = [&]() {
        cout << "garbage:" << x + y << endl;
    };
    stackSpoiler();
}

int main() {
  auto a = captureTest();
  a();
  a();
  garbage(10, 20);
  a();
}

Может кто-то объяснит про лямбды в cpp. Можно ли захватывать локальные переменные и как правильно это делать :) С интересом бы почитал.

Aber ★★★★★
()
Ответ на: комментарий от Aber

В captureTest вы берёте ссылку на переменную на стеке, которая будет удалена в конце captureTest. То есть UB.

Можете добавить static перед int sum = 100; и всё заработает. Но это сломается если вызывать функцию из нескольких потоков.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Я тоже ожидал, что тут будет UB. В исходном сообщении я пытался объяснять почему в java из лямбд нельзя сделать захват локальной переменной, а только захватить ссылку на объект аллоцированный в куче. Но мне начали код кидать на cpp в котором типа все работает.

Aber ★★★★★
()
Последнее исправление: Aber (всего исправлений: 1)
Ответ на: комментарий от Aber

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

TheAnonymous ★★★★★
()
Ответ на: комментарий от TheAnonymous

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

Aber ★★★★★
()
Ответ на: комментарий от Aber

Cишники бесстрашные?

Они просто не такие анскильные лалки

TheAnonymous ★★★★★
()
Ответ на: комментарий от Aber

На C++ можно создавать новый тип данных, и в его экземплярах хранить состояние. И не парить мозг захватом автоматических переменных и UB. Как-то так:

#include <iostream>
#include <optional>
#include <functional>

template<class T>
using NextF = std::function<T(const T&, const T&)>;

template<class T>
struct Sequencer
{
    Sequencer(NextF<T> nextF_): nextF(nextF_) { }

    T operator()(const T& Y)
    {
        return (X = X.has_value() ? nextF(X.value(), Y) : Y).value();
    }

    NextF<T> nextF;
    std::optional<T> X;
};

template<class T> Sequencer(NextF<T>) -> Sequencer<T>;

int main()
{
    auto multF = std::function(std::multiplies<int>());
    auto seq = Sequencer(multF);
    std::cout << seq(3) << std::endl; // В отличие от Java, никакого бойлерплейта с ".get(...)"
    std::cout << seq(4) << std::endl;
    std::cout << seq(5) << std::endl;
}
Наверняка можно и более грамотный вариант сделать, но этот тоже рабочий.

seiken ★★★★★
() автор топика
Последнее исправление: seiken (всего исправлений: 1)
Ответ на: комментарий от Bioreactor

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

Кстати, про разбиение на классы, мидл дескать, джун, синьор-помидор, «тимлид» - это, если что, придумали, чтобы денег не платить. Классификация программистов куда проще галерных лычек.

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

lovesan ★★
()

Можно, а как тебе такое :)

def makesequencer(next_f):
    x = None

    def f(y):
        nonlocal x
        x = y if x is None or not isinstance(y, type(x)) else next_f(x, y)
        return x
    return f


@makesequencer
def make(x, y):
    return x + y


print(make(1), make(5), make(25), make('foo'), make('bar'), make('baz'))
KillTheCat ★★★★★
()
Ответ на: комментарий от lovesan

Сейчас в ДС для тимлида приемлемой считается $4000 в месяц.

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

Для интроверта-отаку типа меня хватает.

В США (Канаде, Западной Европе) тем, кому до 30 лет, надо годик поработать для того, чтобы реально выучить разговорный иностранный язык, приобрести навыки работы в западной компании.

Это дополнительный бонус в CV, который будет учитываться в РФ в крупных компаниях и абсолютно не учитываться (даже наоборот, являться минусом) в компаниях-однодневках.

Bioreactor ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.