Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Michael S Newsgroups: comp.lang.c Subject: Re: technology discussion =?UTF-8?Q?=E2=86=92?= does the world need a "new" C ? Date: Thu, 11 Jul 2024 12:15:02 +0300 Organization: A noiseless patient Spider Lines: 134 Message-ID: <20240711121502.0000614e@yahoo.com> References: <87h6d2uox5.fsf@nosuchdomain.example.com> <20240707164747.258@kylheku.com> <877cdur1z9.fsf@bsb.me.uk> <871q42qy33.fsf@bsb.me.uk> <87ed82p28y.fsf@bsb.me.uk> <87r0c1nzjj.fsf@bsb.me.uk> <86ikxd8czu.fsf@linuxsc.com> <20240710201454.0000527e@yahoo.com> <20240711111357.00007712@yahoo.com> <20240711012852.856@kylheku.com> MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Injection-Date: Thu, 11 Jul 2024 11:14:38 +0200 (CEST) Injection-Info: dont-email.me; posting-host="cc2ba001c5d2368b495ec9c7cf5e7c33"; logging-data="2492964"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1841GjlIPLmRdVlAWjFgKmxZP54No4fE8U=" Cancel-Lock: sha1:+qF8JFOrbaKqNK20+RBsSDoXbRY= X-Newsreader: Claws Mail 3.19.1 (GTK+ 2.24.33; x86_64-w64-mingw32) Bytes: 6430 On Thu, 11 Jul 2024 08:41:14 -0000 (UTC) Kaz Kylheku <643-408-1753@kylheku.com> wrote: > On 2024-07-11, Michael S wrote: > > On Wed, 10 Jul 2024 21:28:15 +0200 > > David Brown wrote: > > > >> On 10/07/2024 19:14, Michael S wrote: > >> > On Wed, 10 Jul 2024 08:48:05 -0700 > >> > Tim Rentsch wrote: > >> > > >> >> bart writes: > >> >> > >> >>> I earlier asked this: > >> >>> > >> >>> "So if arrays aren't passed by value in C, and they aren't > >> >>> passed by reference, then how the hell ARE they passed?!" > >> >> > >> >> They aren't. C allows lots of things to be passed as an > >> >> argument to a function: several varieties of numeric values, > >> >> structs, unions, and pointers, including both pointers to > >> >> object types and pointers to function types. C does not have a > >> >> way for a function to take an argument that is either an array > >> >> or a function. There is a way to take pointers to those > >> >> things, but not the things themselves. Arrays and functions > >> >> are second-class values in C. > >> > > >> > I'd like to see an example of the language that permits > >> > ahead-of-time compilation and has functions as first-class > >> > values. > >> > >> Haskell is the first the comes to mind for me, but you could pick > >> any compiled functional programming language. > >> > >> I am by no means a Haskell expert, and I am not at all familiar > >> with the way the language is compiled. But it is quite clear that > >> it is an example of a language that has functions as first-class > >> objects, and which is ahead-of-time compiled. The example below > >> defines an int-to-int function "doubler", and also a > >> function-to-function function "doTwice", and a function quadrupler > >> that is defined as the result of applying the higher-order > >> function doTwice to doubler. These are all compiled to assembly. > >> > >> > >> > >> > >> module Example where > >> > >> doubler :: Int -> Int > >> doubler x = 2 * x > >> > >> doTwice :: (Int -> Int) -> (Int -> Int) > >> doTwice f x = f (f x) > >> > >> quadrupler = doTwice doubler > >> > >> shouldBeEighty = quadrupler 20 > >> > >> > >> > >> You can write much the same in C++ using lambdas (which are objects > >> and can be passed around and returned as such) and templates (which > >> are needed because the type of lambdas is hidden). Unfortunately, > >> this also means that the functions don't get individually generated > >> functions in assembly: > >> > >> > >> > >> auto doubler = [](int x) -> int { return 2 * x; }; > >> > >> auto doTwice = [](auto f) -> auto > >> { > >> return [f](int x) -> int { return f(f(x)); }; > >> }; > >> > >> auto quadrupler = doTwice(doubler); > >> > >> auto shouldBeEiqhty = quadrupler(20); > >> > > > > I fail to see a material difference between first class function > > values in Haskell and C++ and first class function pointer values > > in C: > > > > int doubler(int x) { > > return x*2; > > } > > int doTwice(int (*foo)(int), int x) { > > return foo(foo(x)); > > } > > int quadrupler(int x) { > > return doTwice(doubler, x); > > } > > > > I am willing to believe that the difference exists, but your > > example is too basic to demonstrate it. > > First class functions could do something like this: > > // multiplier takes a coefficient and returns a pointer to > // function > > int (*multiplier(int coefficient))(int) { > // fantasy lambda syntax. Return type int is written after > // parameter list. > return lambda(int x) int { > return coefficient * x; > } > } > > int (*doubler)(int) = multiplier(2); > > int x = doubler(42); // x becomes 84 > > Even though the lambda is returned out of multiplier, whose execution > terminates, when the returned function is invoked, it can refer to the > coefficient, which is captured in a lexical closure. > > With a C-like typedef, we can declutter the definition of mutiplier: > > typedef int (*int_int_fn)(int); > > int_int_fn multiplier(int coefficient) { > return lambda(int x) int { > return coefficient * x; > } > } > Thank you. Your example confirms my suspicion that the difference between first and second class of functions doesn't become material until language supports closures.