From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by sourceware.org (Postfix) with ESMTPS id D43733858025; Wed, 20 Oct 2021 18:52:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D43733858025 Received: by mail-wr1-x42c.google.com with SMTP id o20so48921236wro.3; Wed, 20 Oct 2021 11:52:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:subject:from:to:cc:date:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=4dMNix+qiIkXSSQgIAkcwWKhUrV5ygLNj2oqCSxiHbE=; b=TB5OFm/mjyw//c02yaImbu7jYG5aMZUpHWvTH0BhExuaNF8pvs4rvHnTItltlXgZ// Sb4an8RpAo1BYLfZ9DmBUC++GH6JBBNFa/7fJ3JU65Yee+Htr+/bY11C1bolYWemJOLP iukMhsJBXH9NbOpZ3mZzcxvNtt4YrlqFbFna+EtjtZxiOl1CBbzzP1wzBIiVMF09QHIq Un3uIEco8j4Xy91VTirwuoqvwV/F1jcF+bLswZ30+LfptLuq8FLHH4qrZFq4GU+PXV0H 9zuhaY92vFCr+ekSIr/THOsXrCzhB53QT2oJHjx/+WIquSqZu30oe7uiwQPfVSg10EC4 OFqA== X-Gm-Message-State: AOAM532CCXgmQ7DjEnBkhOEd5Nvz7EiGv5SZn7S4TuHZhC0JHhSI8mdd 8GeUgP5ShH/pBhEGdrNThA+qCRbrhb4= X-Google-Smtp-Source: ABdhPJzdbHk1wjR9K8NB0e7zOkQFCM00nJulN1g+L6t5Nrg6TTYVts4kjYqUY23dfNi6mzd9LVf3Eg== X-Received: by 2002:adf:959a:: with SMTP id p26mr1138940wrp.342.1634755944914; Wed, 20 Oct 2021 11:52:24 -0700 (PDT) Received: from 2a02-8388-e205-e880-569c-680a-c69b-a1ad.cable.dynamic.v6.surfer.at (2a02-8388-e205-e880-569c-680a-c69b-a1ad.cable.dynamic.v6.surfer.at. [2a02:8388:e205:e880:569c:680a:c69b:a1ad]) by smtp.gmail.com with ESMTPSA id p19sm5659110wmg.29.2021.10.20.11.52.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Oct 2021 11:52:24 -0700 (PDT) Message-ID: Subject: Re: wide function pointer type From: Martin Uecker To: "Kaz Kylheku (libffi)" <382-725-6798@kylheku.com> Cc: Florian Weimer , Martin Uecker via Libffi-discuss , Libffi-discuss Date: Wed, 20 Oct 2021 20:52:23 +0200 In-Reply-To: References: <9362563f8803f575d00c03835d2897b3836a7645.camel@gmail.com> <857da973fe5bbb94a363114262b57d42b35cc1f6.camel@gmail.com> <87czo2hjiq.fsf@oldenburg.str.redhat.com> <8d2ddbb76479ce3ad7f99acb3f0b79a6a8d1440b.camel@gmail.com> <87bl3lgyha.fsf@oldenburg.str.redhat.com> <6a0299e6b3c47cddd88b24d569fca8aeb4717aeb.camel@gmail.com> <87o87lfhi3.fsf@oldenburg.str.redhat.com> Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.30.5-1.1 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libffi-discuss@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libffi-discuss mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 Oct 2021 18:52:27 -0000 Am Mittwoch, den 20.10.2021, 01:24 -0700 schrieb Kaz Kylheku (libffi): > On 2021-10-19 05:13, Martin Uecker via Libffi-discuss wrote: > > void foo( > > void (cb1)(void* data, int a), void* data1, > > void* other_data); > > > > Here a human (and maybe also a machine) could guess > > that data1 belongs to cb1 but not other_data. But > > it is not clear and in more complicated cases > > even less so. > > That's a property of almost every C API. You cannot > guess the properties from the declaration alone. > > If memcpy didn't have the const on the source > argument, you couldn't guess which argument is > the destination and which is the source. The difference here is that something which is a fundamental type in most other languages is split up into two things in C. > y > Argument names and analogy to x tell you > which argument of pow is the base and which the > exponent. > > That's the job of documentation. Generators for language wrappers do not read documentation ;-) > A declarative mechanism which indicates that a given > context parameter goes with a given function could > exist instead of _Wide. Yes, I had considered this too. > Such a thing was introduced 22 years ago for VLA's: > > void fun(int m, double a[m]); Sure, but VLA types are also underdeveloped The limitations are: - You can not store a pointer to a VLA in the struct. - You can not put the size later. - You can not always automatically verify that the size is correct at the caller side because the semantic type of a declaration is: void fun(int m, double a[*]); All this would be avoided with a wide pointer type that integrates the size into the pointer (as in FORTRAN). This was in fact proposed by Dennis Ritchie himself a long time ago: Ritchie DM. Variable-size arrays in C. The Journal of C Language Translation 1990;2:81-86. > An obvious convention is possible, and often occurs > in practice: namely, the context parameter in the API > function is given a name which exactly matches the > one in the function pointer: > > void foo(void (cb1)(void *the_context, int a), > void *unrelated_data, > void *the_context); > > Your proposal also assumes that closures must always > be specified as two argument words, which is an > inappropriate choice to foist onto programmers. No it does not assume this. You can always keep doing this as before. > So that is to say, you're taking it for granted that > you want to keep a distinct disadvantage of the > current approach and just wrap it in some syntactic > sugar machinery so that the two arguments appear > encapsulated as some _Wide thing passed by value. > > But callback interfaces can easily use just a single > argument word to point to a object that is passed > with reference semantics; that object has a function > and context data. I am not sure what you are talking about.. > In high level languages with closures, like Lisp > dialects, closures are of the same "size" as other > values; e.g. 32 or 64 bit pointer-sized word or > what have you. > > C++ callback objects are usually one pointer also. > > void f(CallBackBase *cb) > { > (*cb)(42); // via operator () > // or > cb->callBack(42); // regular member function > } Not at all. C++ has std::function for this purpose which is usually even bigger than two words because it does an optimization for small objects. > C programs do this too: > > void f(struct obj *o) > { > o->ops->callback(o, 42); > } > > Or with the ops table in the object instance: > > void f(struct obj *o) > { > o->ops.callback(o, 42); > } > > The idea that all callback interfaces in C > use a function and a void * argument is a false; you > have to survey the entire field of practice in this general > area. I never claimed that "all callbacks use void*". So please do not use strawman arguments. > > void foo(void (_Wide cb1)(int a), void* other_data); > > Without _Wide, we have > > void (cb1)(int a) > > That (cb1)(int a) is a function declarator (with superfluous > parentheses); but when that occurs as a parameter, it > declares a function pointer: it is equivalent to: > > void (*cb1)(int a) > > But it looks like > > void (_Wide cb1)(int) > > might not be similarly equivalent to > > void (_Wide *cb1)(int) > > and the difference could be useful. > > Furthermore, given that you can have a _Wide value W, or > a pointer to a _Wide value PW, do you call them using different > syntax? > > Is it just W(arg, ...) and PW(arg, ....)? > > Or do we require (*PW)(arg, ...)? > > If we don't require it, is it because of a decay rule, so that > we can write PW(arg, ...) or (*PW)(arg, ...) or (**PW)(arg, ...)? > and same with W? Or is it due to separately articulated semantics: > that the function call operator works with a _Wide and a > pointer-to_Wide, without any "decay" conversion going on? If _Wide is a qualifier as in the proposal Function types nothing changes. Martin