LINUX.ORG.RU

Си с классами

 , ,


0

6

Тупнячка принёс, извиняйте.

Начинаю проект (личный), выбираю на чём писать: C или C++.

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

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

Насколько такой суперсет C / сабсет C++ ака «Си с классами» может быть кошерен?

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

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

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

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

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

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

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

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

ну наверное да, чел прочитавший «с++ для чайников» не напишет реализацию стл. это как-то по-другому должно работать?

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

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

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

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

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

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

Да та же елочка, только синтаксис другой и иначе работает механизм условий и обработка неудачного исхода этих условий

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

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

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

Здесь твоя ошибка заключается в том, что ты считаешь ad-hoc чем-то плохим. Попытка покрыть всех абстрактных коней в вакууме обречена на то, чтобы в очередной раз столкнуться с непокрытым конем, и сделать библиотеку еще более абстрактной и вакуумной. Просто для того, чтобы на ней продолжили клепать в большинстве случаев хело ворлды, которые не используют даже 10% фич абстрактной либы.

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

Хм… ну так а я о чем… та же елка только в профиль. Ты говоришь что изначальный код был более линейный. Но, исполняемая среда по определению не умеет в линейность, если суть кода условные выражения, можно посмотреть на то, во что выльется тот «линейный» код в промежуточном представлении? Там же вроде за f# была беседа, значит можно получить ил представление, правда оно вроде отличаться должно от того что обычно генерируется для дотнета Давай посмотрим что там получится, если у тебя есть под рукой нужный тулчейн. Я понимаю что за ворохом абстракций, особенно хороших сложнее делать ошибки, понимаю почему итератор в java стиле тебе нравится больше, но все же хотелось бы узнать что там под ковром.

anonymous ()
Ответ на: комментарий от byko3y

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

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

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

anonymous ()
Ответ на: комментарий от byko3y

Ты предложил переопределить зарезервированный идентификатор первым.

О чем вы сейчас вообще?

define_variant — это такой же идентификатор, как std::variant.

  1. Где здесь «зарезервированный идентификатор»?

  2. Где я предлагал что-то переопределить?

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

Где здесь «зарезервированный идентификатор»?
Где я предлагал что-то переопределить?

Разговор был про вот это:

Тем, что у Васи Пупкина свой define_variant, а у Пети Иванова – свой. И никак они друг с другом не связаны

Так вот прикол: у STL есть разные реализации. Сюрприз? Да, у них похожий интерфейс, и иногда даже похожее поведение. Что, оданко, не мешает мне сделать STL с непохожим поведением, и вообще не STL.

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

Во-первых, не вижу ответов на прямые вопросы, а именно:

  1. Где здесь «зарезервированный идентификатор»?
  2. Где я предлагал что-то переопределить?

Может вы разберетесь с тараканами в вашей башке и сможете таки ответить на два простых вопроса.

Во-вторых, вот это фееричное:

Что, оданко, не мешает мне сделать STL с непохожим поведением, и вообще не STL.

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

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

Там же вроде за f# была беседа, значит можно получить ил представление, правда оно вроде отличаться должно от того что обычно генерируется для дотнета Давай посмотрим что там получится, если у тебя есть под рукой нужный тулчейн

Получается набор вот таких однообразных обобщенных классов-функций:

.method public strict virtual instance class Program/Result`2<!a,!b> 
        Invoke(!a _arg2) cil managed
{
  // Code size       32 (0x20)
  .maxstack  7
  .locals init ([0] !a r2)
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  stloc.0
  IL_0003:  ldarg.0
  IL_0004:  ldfld      class Program/ResultBuilder class Program/'res@28-1'<!a,!b>::builder@
  IL_0009:  ldloc.0
  IL_000a:  call       class Program/Result`2<!!0,!!1> Program::doJob3<!a,!b>(!!0)
  IL_000f:  ldarg.0
  IL_0010:  ldfld      class Program/ResultBuilder class Program/'res@28-1'<!a,!b>::builder@
  IL_0015:  newobj     instance void class Program/'res@29-2'<!a,!b>::.ctor(class Program/ResultBuilder)
  IL_001a:  callvirt   instance class Program/Result`2<!!2,!!1> Program/ResultBuilder::Bind<!a,!b,!a>(class Program/Result`2<!!0,!!1>,
                                                                                                      class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!!0,class Program/Result`2<!!2,!!1>>)
  IL_001f:  ret
} // end of method 'res@28-1'::Invoke

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

На псевдоязыке можно переписать эти функции примерно так:

method res29<TResult, TError>(arg) {
	return result::Return<int32, object>(arg);
}

method res28<TResult, TError>(arg) {
	return result::Bind<TResult, TError>(doJob3<TResult, TError>(arg), res29);
}

method res27<TResult, TError>(arg) {
	return result::Bind<TResult, TError>(doJob2<TResult, TError>(arg), res28);
}

method res<TResult, TError>(arg) {
	return result::Bind<TResult, TError>(doJob<TResult, TError>(arg), res27);
}

method main() {
	r = res<int32, object>(0)
	if isinstance(r, Ok<int32,object>)
		return Ok<int32,object>(r).item;
	else
		return 1;
}

То есть, что-то очень близкое к функторам-монадам хаскеля.

Исходная программа целиком выглядела так:

type Result<'TResult, 'TError> =
    | Ok of 'TResult
    | Error of 'TError

type ResultBuilder() =
    member __.Bind(x, f) =
        match x with
        | Error e -> Error e
        | Ok x -> f x
    member __.Return x = Ok x
    member __.ReturnFrom x = x

let result = ResultBuilder()

let doJob a = Ok a
let doJob2 a = Ok a
let doJob3 a = Ok a

let res arg =
    result {
        let! r = doJob arg
        let! r2 = doJob2 r
        let! r3 = doJob3 r2
        return r3
    }

[<EntryPoint>]
let main argv = 
    match res(0) with
    | Error e -> 1
    | Ok r -> r
byko3y ★★ ()
Ответ на: комментарий от anonymous

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

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

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

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

IL_0015: newobj instance void class Program/‘res@29-2’<!a,!b>::.ctor(class Program/ResultBuilder)

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

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

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

Это IL. При компиляции в код целевой системы никто ничего в куче не выделяет. Также в листинге отсутствует инструкция tail, которая генерируется в релизном билде и подсказывает о необходимости оптимизации хвостовой рекурсии в res, res27, и res28. Более того, все они в итоге станут линейным кодом, без каких-либо вызовов функций.

Предлагаю на досуге сравнения крестовый IL до оптимизаций.

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

крестовый IL до оптимизаций.

хорошо.

в принципе это примерно то же самое, что фсб4к написал, только он это написал на с++ и ему не нужен был никакой ил или рантайм от майкрософта, он просто взял и написал, и ничего даже алоцировать не пришлось и не было промежуточных объектов.

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

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

Я не знаю как получить JIT ASM код, но вот код который показывается в отладчике(release build):

[<EntryPoint>]
let main argv = 
  match res(0) with
00007FF86C7308A0  push        rbp  
00007FF86C7308A1  sub         rsp,30h  
00007FF86C7308A5  lea         rbp,[rsp+30h]  
00007FF86C7308AA  xor         eax,eax  
00007FF86C7308AC  mov         qword ptr [rbp-8],rax  
00007FF86C7308B0  mov         qword ptr [rbp+10h],rcx  
00007FF86C7308B4  mov         rcx,7FF86C7CEF10h  
00007FF86C7308BE  mov         edx,0Ch  
00007FF86C7308C3  call        CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE (07FF8CC237B50h)  
00007FF86C7308C8  mov         dword ptr [7FF86C7CEF50h],0  
00007FF86C7308D2  mov         rcx,7FF86C7CEF10h  
00007FF86C7308DC  mov         edx,0Ch  
00007FF86C7308E1  call        CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE (07FF8CC237B50h)  
00007FF86C7308E6  mov         rcx,7FF86C7F2090h  
00007FF86C7308F0  xor         edx,edx  
00007FF86C7308F2  call        CLRStub[MethodDescPrestub]@7ff86c7302d8 (07FF86C7302D8h)  
00007FF86C7308F7  mov         qword ptr [rbp-8],rax  
00007FF86C7308FB  mov         rdx,qword ptr [rbp-8]  
00007FF86C7308FF  mov         rcx,7FF86C7F2710h  
00007FF86C730909  call        00007FF8CC236660  
00007FF86C73090E  test        rax,rax  
00007FF86C730911  je          Program.main(System.String[])+08Fh (07FF86C73092Fh)  
  | Ok r -> r
00007FF86C730913  mov         rdx,qword ptr [rbp-8]  
00007FF86C730917  mov         rcx,7FF86C7F2710h  
00007FF86C730921  call        00007FF8CC2366F0  
00007FF86C730926  mov         eax,dword ptr [rax+8]  
00007FF86C730929  lea         rsp,[rbp]  
00007FF86C73092D  pop         rbp  
00007FF86C73092E  ret
  | Error e -> 1
00007FF86C73092F  mov         eax,1  
00007FF86C730934  lea         rsp,[rbp]  
00007FF86C730938  pop         rbp  
00007FF86C730939  ret 

https://imgur.com/a/CGseE6L

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

х ево з, что он делает, но это не «линейный код без каких-то вызовов функций».

00007FF86C7308C3  call        CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE (07FF8CC237B50h)  
...
00007FF86C7308E1  call        CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE (07FF8CC237B50h)  
...
00007FF86C7308F2  call        CLRStub[MethodDescPrestub]@7ff86c7302d8 (07FF86C7302D8h)  
...
00007FF86C730909  call        00007FF8CC236660  

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

anonymous ()
Ответ на: комментарий от fsb4000

код который показывается в отладчике(release build)

Если бы оптимизировал, то должен был тупо вернуть 0. А тут вызов на вызове вызовом погоняет.

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

Для C# есть https://sharplab.io/

(аналог godbolt для c++/pascal/rust)

Но с F# он нормально не работает :(

Но там можно конвертнуть F# в C#

насколько я понимаю исходник, это всё должно было задекеиться в return 0.

Да

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

Я не знаю как получить JIT ASM код, но вот код который показывается в отладчике(release build)

Да никак ты не получишь JIT-компилированный код, если ты не разраб из MS. AOT компиляцию в .NET Native, насколько мне известно, еще не допилили для F#, потому что никак не разберутся с printf и toString.

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

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

Теперь примени своё же высказывание к ЯП высокого уровня, которые чище, краше, яснее и т.п. ИМХО - ты сам себе противоречишь.

По поводу нестандартных деклараций в C и стандартных в C++ - ты правда не понимаешь, о чём пишешь или прикидываешься?

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

У тебя реально в голове каша. К 14-й вкладке это становится всё более и более очевидным.

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

Теперь примени своё же высказывание к ЯП высокого уровня, которые чище, краше, яснее и т.п. ИМХО - ты сам себе противоречишь

Ты сам придумал в своей голове противоречие и сдетектирвал его. Почему-то вместо «я не понял тебя» ты пишешь «ты сам себе противоречишь». Я ж могу ответить «да, противоречу» — и тебе придется смириться с этим, потому что вот такой вот я. Да, каша в голове. Всё, 15-ой вкладки не будет, я устал.

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

Спасибо.

Ну тогда отвечу на вот это:

let res arg =
    result {
        let! r = doJob arg
        let! r2 = doJob2 r
        let! r3 = doJob3 r2
        return r3
    }

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

По моему, получается не хуже и без «конских описаний типов»:

fn res(arg: T) -> Result<T, E> {
    let r = doJob(arg)?;
    let r2 = doJob2(r)?;
    doJob3(r2)
}
DarkEld3r ★★★★★ ()