Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

inline

28 views
Skip to first unread message

jacob navia

unread,
May 13, 2012, 4:18:41 PM5/13/12
to
It is impossible to declare inline a member of a function table:

struct Interface = {
inline int (*pFn)(double);
inline int (*pFn1)(char *);
};

Is there any way to convey the information to the compiler???

Are there any plans to fill this hole in the language?

Thanks

Martin Shobe

unread,
May 13, 2012, 5:47:45 PM5/13/12
to
jacob navia wrote:

> It is impossible to declare inline a member of a function table:
>
> struct Interface = {
> inline int (*pFn)(double);
> inline int (*pFn1)(char *);
> };
>
> Is there any way to convey the information to the compiler???
>
No.

> Are there any plans to fill this hole in the language?

What hole? I personally can't think of any reasonable semantics to apply
to such a construct.

Martin Shobe

Ian Collins

unread,
May 13, 2012, 6:15:31 PM5/13/12
to
A C++ compiler can inline a virtual member function call if it knows the
exact type of the object. So why can't you just leave the decision to
inline to the compiler in this case?

Given

struct Interface {
int (*pFn)(double);
int (*pFn1)(char *);
};

int d(double dd) { return 42; }
int c(char* cc) { return 21; }

int f( int );

void run() {
struct Interface i = { d, c };

f( i.pFn(0.0) );
}

The compiler could inline the call to i.pFn. I don't know if any would.

--
Ian Collins

BGB

unread,
May 13, 2012, 6:24:00 PM5/13/12
to
maybe the "hole" is whatever semantics he intends to apply to this
construct?

off hand, I have little idea what sort of semantics are intended, as I
haven't seen any "obviously similar" constructs in other languages.

Ian Collins

unread,
May 13, 2012, 6:48:00 PM5/13/12
to
On 05/14/12 10:24 AM, BGB wrote:
> On 5/13/2012 2:47 PM, Martin Shobe wrote:
>> jacob navia wrote:
>>
>>> It is impossible to declare inline a member of a function table:
>>>
>>> struct Interface = {
>>> inline int (*pFn)(double);
>>> inline int (*pFn1)(char *);
>>> };
>>>
>>> Is there any way to convey the information to the compiler???
>>>
>> No.
>>
>>> Are there any plans to fill this hole in the language?
>>
>> What hole? I personally can't think of any reasonable semantics to apply
>> to such a construct.
>
> off hand, I have little idea what sort of semantics are intended, as I
> haven't seen any "obviously similar" constructs in other languages.

One "obviously similar" construct is C++ pure virtual functions. For
example, given

int n;

struct B { virtual void f() = 0; };
struct D1 : B { void f() { n = 1; } };
struct D2 : B { void f() { n = 2; } };

void g(int);

B& get();

void run() {
D1().f();

g(n);

get().f();

g(n);
}

g++ will inline away the call to "D1().f()" because it knows the exact
type, but it can't inline the call to "get().f()" because it doesn't
know the exact type.

Unfortunately gcc doesn't appear to do the same with version of Jacob's
code I posted else-thread.

--
Ian Collins

Jens Gustedt

unread,
May 13, 2012, 6:53:31 PM5/13/12
to Ian Collins
Hello,
I basically agree with you. But to be suitable for header files you'd
have to add some sugar to this

Am 14.05.2012 00:15, schrieb Ian Collins:
> struct Interface {
> int (*pFn)(double);
> int (*pFn1)(char *);
> };

struct Interface {
int (*const pFn)(double);
int (*const pFn1)(char *);
};


> int d(double dd) { return 42; }
> int c(char* cc) { return 21; }

these two would have to be inline, and then you'd need to have the
symbols emitted in some compilation unit.

> int f( int );
>
> void run() {
> struct Interface i = { d, c };

this one would have to be a macro that produces a const qualified
compound literal (or a static const variable)

#define myInterface ((const struct Interface){ .pFn = d, .pFn1 = c, })

or even better a const qualified rvalue

#define myInterface (const struct Interface)((const struct Interface){
.pFn = d, .pFn1 = c, })

>
> f( i.pFn(0.0) );

f(myInterface.pFn(0.0));

> }
>
> The compiler could inline the call to i.pFn. I don't know if any would.

I think I have seen such things working with gcc, but in general it is
probably better that all this stuff would be const qualified rvalues
to assert that the function (pointer) can never change.

Jens

Ian Collins

unread,
May 13, 2012, 7:20:19 PM5/13/12
to
On 05/14/12 10:53 AM, Jens Gustedt wrote:
> Hello,
> I basically agree with you. But to be suitable for header files you'd
> have to add some sugar to this
>
> Am 14.05.2012 00:15, schrieb Ian Collins:
>> struct Interface {
>> int (*pFn)(double);
>> int (*pFn1)(char *);
>> };
>
> struct Interface {
> int (*const pFn)(double);
> int (*const pFn1)(char *);
> };

That would be closer to a C++ virtual function.

>> int d(double dd) { return 42; }
>> int c(char* cc) { return 21; }
>
> these two would have to be inline, and then you'd need to have the
> symbols emitted in some compilation unit.

The compiler will take care of the inlining, but as you say, everything
has to be visible in the same compilation unit.

>> int f( int );
>>
>> void run() {
>> struct Interface i = { d, c };
>
> this one would have to be a macro that produces a const qualified
> compound literal (or a static const variable)
>
> #define myInterface ((const struct Interface){ .pFn = d, .pFn1 = c, })
>
> or even better a const qualified rvalue
>
> #define myInterface (const struct Interface)((const struct Interface){
> ..pFn = d, .pFn1 = c, })

Both gcc and I had trouble parsing that...

>>
>> f( i.pFn(0.0) );
>
> f(myInterface.pFn(0.0));
>
>> }
>>
>> The compiler could inline the call to i.pFn. I don't know if any would.
>
> I think I have seen such things working with gcc, but in general it is
> probably better that all this stuff would be const qualified rvalues
> to assert that the function (pointer) can never change.

Applying your changes gives gcc enough hints to inline the call. But
they would probably be to cumbersome for general use. Consider a struct
with data and function pointer members for example.

--
Ian Collins

BGB

unread,
May 13, 2012, 7:26:06 PM5/13/12
to
On 5/13/2012 3:15 PM, Ian Collins wrote:
> On 05/14/12 08:18 AM, jacob navia wrote:
>> It is impossible to declare inline a member of a function table:
>>
>> struct Interface = {
>> inline int (*pFn)(double);
>> inline int (*pFn1)(char *);
>> };
>>
>> Is there any way to convey the information to the compiler???
>>
>> Are there any plans to fill this hole in the language?
>
> A C++ compiler can inline a virtual member function call if it knows the
> exact type of the object. So why can't you just leave the decision to
> inline to the compiler in this case?
>

this is possible, but brings up the question of what that "=" is doing
there?...


> Given
>
> struct Interface {
> int (*pFn)(double);
> int (*pFn1)(char *);
> };
>
> int d(double dd) { return 42; }
> int c(char* cc) { return 21; }
>
> int f( int );
>
> void run() {
> struct Interface i = { d, c };
>
> f( i.pFn(0.0) );
> }
>
> The compiler could inline the call to i.pFn. I don't know if any would.
>

yeah, this is a possible optimization.
in this case, it could possibly be seen as a form of constant propagation.

in this case, I would expect wouldn't the inline hint be put on the
functions themselves, since either way the compiler is going to need to
be able to see them.

or, they could be done sort of like in GCC:
extern inline int d(double dd) { return 42; }
extern inline int c(char* cc) { return 21; }

static struct Interface i = { d, c };
...
i.pfn(1.0);

where the compiler infers that it can replace the expression with '42'.


actually... although not C, my scripting language sort of does some
stuff like this already, though in this case it is more related to a mix
of type-inference, constant propagation, and trying to make sense of the
scope model (this one is not really addressed at present).

(the issue is partly that the language is dynamically-typed (partly),
partly uses a Self-like scoping model, and internally represents
"packages" and "imports" as objects and variables, although the compiler
assumes that imports and packages are immutable).

actually, the language also uses static type declarations as well, which
serve both as an optimization hint and also to allow the compiler to
"enforce" known types, since if the programmer declares a variable as a
particular type, the compiler then has the right to complain if it is
given an incompatible type (rather than leaving it up to a run-time
type-check).

actually, I before ended up writing to someone about it, but it seems my
strategy might be sort of an inverted form of the "Hindley-Milner"
system (and without all the esoteric math either), basically where HM
seems to try to start at the final expression and work backwards. in my
case, I assume variables are mutable, and that types and values are
propagated forwards by assignment (or declarations, where a declaration
is treated similarly to an assignment).

so, the basic strategy is:
whenever a value of known constant value and/or type is assigned to a
variable, this variable picks up the constant value and/or type (sort
of, if the current location is inside of a branch, and it doesn't match,
then it will "invalidate" the prior value following the branch, at which
point the value and/or type is no longer known).


but, yeah, little says a C compiler couldn't do stuff sort of like this,
like infer that a chain of function-pointer assignments goes back to an
original (known) function, and either insert a direct call or inline the
function instead.

actually, all this would be complicated some by a few things:
doing this effectively would require visibility across compilation
units, essentially requiring the compiler to work "a library at a time".

many functions may be called from outside the library, which would
mandate that "generic versions" still exist, although on a target like
Windows where DLL exports are declared explicitly, the compiler could
optimize for functions which are not DLL exports.


or such...

BGB

unread,
May 13, 2012, 7:28:50 PM5/13/12
to
On 5/13/2012 3:48 PM, Ian Collins wrote:
> On 05/14/12 10:24 AM, BGB wrote:
>> On 5/13/2012 2:47 PM, Martin Shobe wrote:
>>> jacob navia wrote:
>>>
>>>> It is impossible to declare inline a member of a function table:
>>>>
>>>> struct Interface = {
>>>> inline int (*pFn)(double);
>>>> inline int (*pFn1)(char *);
>>>> };
>>>>
>>>> Is there any way to convey the information to the compiler???
>>>>
>>> No.
>>>
>>>> Are there any plans to fill this hole in the language?
>>>
>>> What hole? I personally can't think of any reasonable semantics to apply
>>> to such a construct.
>>
>> off hand, I have little idea what sort of semantics are intended, as I
>> haven't seen any "obviously similar" constructs in other languages.
>
> One "obviously similar" construct is C++ pure virtual functions. For
> example, given
>

it didn't seem obvious to me that this is what he had intended.

it would have been more obvious if that "=" weren't there, but I had
some major doubts regarding what that "=" meant.

Martin Shobe

unread,
May 13, 2012, 7:35:12 PM5/13/12
to
Ian Collins wrote:

> On 05/14/12 10:24 AM, BGB wrote:
>> On 5/13/2012 2:47 PM, Martin Shobe wrote:
>>> jacob navia wrote:
>>>
>>>> It is impossible to declare inline a member of a function table:
>>>>
>>>> struct Interface = {
>>>> inline int (*pFn)(double);
>>>> inline int (*pFn1)(char *);
>>>> };
>>>>
>>>> Is there any way to convey the information to the compiler???
>>>>
>>> No.
>>>
>>>> Are there any plans to fill this hole in the language?
>>>
>>> What hole? I personally can't think of any reasonable semantics to apply
>>> to such a construct.
>>
>> off hand, I have little idea what sort of semantics are intended, as I
>> haven't seen any "obviously similar" constructs in other languages.
>
> One "obviously similar" construct is C++ pure virtual functions. For
> example, given
>

[snip c++ example]

> Unfortunately gcc doesn't appear to do the same with version of Jacob's
> code I posted else-thread.

So the inline keyword would be meaningless as it becomes just a push for
compilers to more aggressively inline calls via function pointers when
the compiler can be reasonably expected to know exactly which function
was pointed to.

Martin Shobe

Ian Collins

unread,
May 13, 2012, 7:50:20 PM5/13/12
to
Isn't that the case now? The inline keyword has never been more than a
hint.

--
Ian Collins

Ian Collins

unread,
May 13, 2012, 7:52:25 PM5/13/12
to
On 05/14/12 11:26 AM, BGB wrote:
> On 5/13/2012 3:15 PM, Ian Collins wrote:
>> On 05/14/12 08:18 AM, jacob navia wrote:
>>> It is impossible to declare inline a member of a function table:
>>>
>>> struct Interface = {
>>> inline int (*pFn)(double);
>>> inline int (*pFn1)(char *);
>>> };
>>>
>>> Is there any way to convey the information to the compiler???
>>>
>>> Are there any plans to fill this hole in the language?
>>
>> A C++ compiler can inline a virtual member function call if it knows the
>> exact type of the object. So why can't you just leave the decision to
>> inline to the compiler in this case?
>>
>
> this is possible, but brings up the question of what that "=" is doing
> there?...

I assumed it was a typo...

--
Ian Collins

Martin Shobe

unread,
May 13, 2012, 8:25:11 PM5/13/12
to
I don't think so. The inline keyword also allows the function to be
defined in multiple translation units. (See 6.7.4.7)

Martin Shobe

Martin Shobe

unread,
May 13, 2012, 8:27:20 PM5/13/12
to
I did too. I think he meant something like

struct interface foo = {
inline int (*pFn)(double);
inline int (*pFn1)(char *);
};

Martin Shobe

Ian Collins

unread,
May 13, 2012, 8:41:55 PM5/13/12
to
I should have written "In the context of optimisation, the inline
keyword has never been more than a hint."

--
Ian Collins

Martin Shobe

unread,
May 13, 2012, 8:51:23 PM5/13/12
to
I'll agree with that, but in this context would the inline have any
other purpose than providing that hint?

Martin Shobe

BGB

unread,
May 13, 2012, 8:51:24 PM5/13/12
to
fair enough.
I took the "=" at face value, but couldn't make much sense of what was
supposed to be being assigned to what.

had thought maybe it was intended as something (vaguely) sort of like
anonymous classes in Java, except that in this case one would presumably
supply functions directly.


for example:

struct Interface foo =
{
inline int pFn(double) { return 42; }
inline int pFn1(char *) { return 13; }
};

which could do something sort of like:

inline int pFn(double) { return 42; }
inline int pFn1(char *) { return 13; }

struct Interface foo =
{
pFn,
pFn1
};


or such...


> Martin Shobe
>

Miles Bader

unread,
May 14, 2012, 1:24:02 AM5/14/12
to
Ian Collins <ian-...@hotmail.com> writes:
...
> The compiler could inline the call to i.pFn. I don't know if any would.

gcc 4.7+ will inline everything as given. Earlier versions don't seem
to... [I think 4.7 saw a pretty give revamp of inlining heuristics.]

-miles

--
"Though they may have different meanings, the cries of 'Yeeeee-haw!' and
'Allahu akbar!' are, in spirit, not actually all that different."

jacob navia

unread,
May 14, 2012, 1:32:26 AM5/14/12
to
Le 13/05/12 22:18, jacob navia a écrit :
> It is impossible to declare inline a member of a function table:
>
Specifically, I intended this


typedef struct _Interface = {
inline int (*Deg2rad)(double);
inline int (*pFn1)(char *);
} Interface;

inline int Interface.Deg2Rad(double arg)
{
return arg/57.295;
}

I would define this way that the member "Deg2rad" has that
code.

Obviously assignment to those function members would be forbidden or
would be an error.

jacob navia

unread,
May 14, 2012, 1:43:31 AM5/14/12
to
Le 14/05/12 00:53, Jens Gustedt a écrit :
> Hello,
> I basically agree with you. But to be suitable for header files you'd
> have to add some sugar to this
>
> Am 14.05.2012 00:15, schrieb Ian Collins:
>> struct Interface {
>> int (*pFn)(double);
>> int (*pFn1)(char *);
>> };
>
> struct Interface {
> int (*const pFn)(double);
> int (*const pFn1)(char *);
> };
>
>
>> int d(double dd) { return 42; }
>> int c(char* cc) { return 21; }
>
> these two would have to be inline, and then you'd need to have the
> symbols emitted in some compilation unit.

How can the compiler prove that those symbols aren't assigned to other
functions during the run time?

That is the problem!

It *could* be. OK the "const" is mandatory, but still, the
compiler needs to see the whole initialization. That can be
tricky, specially for a library.

To write that in a header file you would need to initialize ALL
members in that header file.

jacob navia

unread,
May 14, 2012, 1:46:27 AM5/14/12
to
Le 14/05/12 02:51, Martin Shobe a écrit :
It would be simpler if we could do

typedef struct _Interface = {
inline int (const *Deg2rad)(double);
inline int (*pFn1)(char *);
} Interface;

inline int Interface.Deg2Rad(double arg)
{
return arg/57.295;
}

That way we say:

The function in Interface.Deg2rad is this one and it is not going to
change"

Jens Gustedt

unread,
May 14, 2012, 2:38:37 AM5/14/12
to
Am 14.05.2012 01:20, schrieb Ian Collins:
> On 05/14/12 10:53 AM, Jens Gustedt wrote:
>> struct Interface {
>> int (*const pFn)(double);
>> int (*const pFn1)(char *);
>> };
>
> That would be closer to a C++ virtual function.

exactly


>> #define myInterface ((const struct Interface){ .pFn = d, .pFn1 = c, })
>>
>> or even better a const qualified rvalue
>>
>> #define myInterface (const struct Interface)((const struct Interface){
>> ..pFn = d, .pFn1 = c, })
>
> Both gcc and I had trouble parsing that...

argh, in the later there is one "." too much, sorry. The idea for the
first is to use a const qualified compound literal. Since it is const
qualified, the compiler has the possibility to fold all occurences
with the same value into one object.

The second (corrected :) version makes it an rvalue by casting it to
the same type. Thereby we also give the compiler the guarantee that
the address of that object is never taken, so it can't change under
the hood. That is a variant of declaring a const qualified "register"
object in file scope, if you want.

> Applying your changes gives gcc enough hints to inline the call. But
> they would probably be to cumbersome for general use. Consider a struct
> with data and function pointer members for example.

Cumbersome to write, yes. But as easy to use as the originial one.

Jens



Jens Gustedt

unread,
May 14, 2012, 2:42:23 AM5/14/12
to
Am 14.05.2012 07:43, schrieb jacob navia:
> Le 14/05/12 00:53, Jens Gustedt a écrit :
> How can the compiler prove that those symbols aren't assigned to other
> functions during the run time?

see my reply to Ian. You'd have to use a const qualified global object
where you can't take an address. C as for now has no other possibility
to make this through an rvalue.

(I'd really like to see file scope const register variables one day in
the language)

> It *could* be. OK the "const" is mandatory, but still, the
> compiler needs to see the whole initialization. That can be
> tricky, specially for a library.
>
> To write that in a header file you would need to initialize ALL
> members in that header file.

yes, I would use the macro as I have given it previously (with the
error corrected), but that's me, not everybody is as happy with using
macros :)

Jens



Ian Collins

unread,
May 14, 2012, 4:52:25 AM5/14/12
to
On 05/14/12 05:24 PM, Miles Bader wrote:
> Ian Collins<ian-...@hotmail.com> writes:
> ....
>> The compiler could inline the call to i.pFn. I don't know if any would.
>
> gcc 4.7+ will inline everything as given. Earlier versions don't seem
> to... [I think 4.7 saw a pretty give revamp of inlining heuristics.]

Upgrade time then! Thanks for the tip.

--
Ian Collins

Ian Collins

unread,
May 14, 2012, 4:56:21 AM5/14/12
to
You keep trying to push C++ style features into C (in incompatible
ways), so why don't you just use C++? The original 90s cfront dialect
does everything you want to add to C.

--
Ian Collins

jacob navia

unread,
May 14, 2012, 5:44:06 AM5/14/12
to
Le 14/05/12 10:56, Ian Collins a écrit :
>
> You keep trying to push C++ style features into C (in incompatible
> ways), so why don't you just use C++? The original 90s cfront dialect
> does everything you want to add to C.
>

Excuse me but C has "inline" already, even if that is a "C++ feature".

What I am saying is that it is impossible to use in a specific
situation and I am asking to correct that.

That's all.


Ian Collins

unread,
May 14, 2012, 5:55:36 AM5/14/12
to
On 05/14/12 09:44 PM, jacob navia wrote:
> Le 14/05/12 10:56, Ian Collins a écrit :
>>
>> You keep trying to push C++ style features into C (in incompatible
>> ways), so why don't you just use C++? The original 90s cfront dialect
>> does everything you want to add to C.
>>
>
> Excuse me but C has "inline" already, even if that is a "C++ feature".

I was referring to the struct.member function definition syntax.

> What I am saying is that it is impossible to use in a specific
> situation and I am asking to correct that.

I think it's quite clear from the earlier discussions that inline is
pointless in this context. If the compiler can inline, it will and to
do that it has to be able to see all the definitions.

--
Ian Collins

jacob navia

unread,
May 14, 2012, 7:50:04 AM5/14/12
to
Le 14/05/12 11:55, Ian Collins a écrit :
>
> I think it's quite clear from the earlier discussions that inline is
> pointless in this context. If the compiler can inline, it will and to do
> that it has to be able to see all the definitions.
>

Well that is exactly the problem. Those definitions can be in a library
and not all of them will be inlined. So, I am proposing that the user
specifies that THIS member will be inlined with

inline resultType Interface.function(args) { }

This is quite readable. In the Interface definition that function
must be marked as const.



Martin Shobe

unread,
May 14, 2012, 8:02:40 AM5/14/12
to
Ok. I'm even more confused now. I still don't have any idea what you
intend inline to mean, and it's now starting to appear that the '='
isn't a typo, so I also have no idea what it means.

What exactly are the semantics that you intend for this construct.

Martin Shobe

jacob navia

unread,
May 14, 2012, 10:11:42 AM5/14/12
to
Le 14/05/12 14:02, Martin Shobe a écrit :
>
> Ok. I'm even more confused now. I still don't have any idea what you
> intend inline to mean, and it's now starting to appear that the '='
> isn't a typo, so I also have no idea what it means.
>
> What exactly are the semantics that you intend for this construct.
>
> Martin Shobe
>

The "=" is a typo and I pasted the error in this new message.
I am sorry. I am probably overworked and very tired.

What I need to do is the following:

This is an interface:

typedef struct interface {
int (const *Deg2Rad)(double foo);
double (*doubleFn)(double foo);
char *SomeData;
double complex MoreData;
} Interface;

Now, I want to say that the member "Deg2Fn" is the following
INLINE function:

inline int Interface.Deg2Rad(double foo) { return foo/57.295; }


You see?

I propose that when defining an inline function, we can specify
a structure member (with matching prototype of course) so that
the compiler knows that all calls to:

Interface.Deg2fn(180.0)

can be safely replaced with the inlined function.

I will post a new message again to clarify.

jacob

Ike Naar

unread,
May 14, 2012, 10:31:17 AM5/14/12
to
On 2012-05-14, jacob navia <ja...@spamsink.net> wrote:
> What I need to do is the following:
>
> This is an interface:
>
> typedef struct interface {
> int (const *Deg2Rad)(double foo);
> double (*doubleFn)(double foo);
> char *SomeData;
> double complex MoreData;
> } Interface;
>
> Now, I want to say that the member "Deg2Fn" is the following
> INLINE function:
>
> inline int Interface.Deg2Rad(double foo) { return foo/57.295; }
>
>
> You see?
>
> I propose that when defining an inline function, we can specify
> a structure member (with matching prototype of course) so that
> the compiler knows that all calls to:
>
> Interface.Deg2fn(180.0)

Assuming you mean Interface.Deg2Rad(180.0) here.

> can be safely replaced with the inlined function.
>
> I will post a new message again to clarify.

Isn't it a bit unusual to associate the inlined function with
the _type_ Interface, instead of instances of the type?

In general, there can be several objects of the type, each having
their own Deg2Rad member, like in:

double deg2rad_0(double};
double deg2rad_1(double};
Interface interface_0 = {deg2rad_0, 0, 0, 0};
Interface interface_1 = {deg2rad_1, 0, 0, 0};

When inlining Interface.Deg2Rad, are you going to disallow the
definition of objects of type Instance, like the ones given above?

jacob navia

unread,
May 14, 2012, 11:08:57 AM5/14/12
to
Le 14/05/12 16:31, Ike Naar a écrit :
>> Interface.Deg2fn(180.0)
>
> Assuming you mean Interface.Deg2Rad(180.0) here.
>

of course. Yet again a typo (YAAT!!!!)

>> can be safely replaced with the inlined function.
>>
>> I will post a new message again to clarify.
>
> Isn't it a bit unusual to associate the inlined function with
> the _type_ Interface, instead of instances of the type?
>
> In general, there can be several objects of the type, each having
> their own Deg2Rad member, like in:
>
> double deg2rad_0(double};
> double deg2rad_1(double};
> Interface interface_0 = {deg2rad_0, 0, 0, 0};
> Interface interface_1 = {deg2rad_1, 0, 0, 0};
>
> When inlining Interface.Deg2Rad, are you going to disallow the
> definition of objects of type Instance, like the ones given above?

Of course it is disallowed.

What you say with this construct is that ALL instances of that
type (that is why the TYPE name is needed) use that inlined function.

This allows the compiler to always generate the inlined code
in all cases.

If you would tie that to one instance the compiler would need to know
the initiliazation of that instance and ALL problems we want to avoid
would reappear again.

AGAIN:
Basically you are saying:

ALL instances of this type will have this member inlined to this
function.

jacob

Wojtek Lerch

unread,
May 14, 2012, 4:30:58 PM5/14/12
to
On 14-May-12 10:11 AM, jacob navia wrote:
> This is an interface:
>
> typedef struct interface {
> int (const *Deg2Rad)(double foo);
> double (*doubleFn)(double foo);
> char *SomeData;
> double complex MoreData;
> } Interface;
>
> Now, I want to say that the member "Deg2Fn" is the following
> INLINE function:
>
> inline int Interface.Deg2Rad(double foo) { return foo/57.295; }

It seems that you basically want to be able to specify that member X of
structure Y must always be initialized to the same value in every object
whose type is Y (or maybe just every explicitly initialized Y object).
In this example, you want every object defined as an Interface to have
its Deg2Rad member initialized to the address of the same function, to
allow the compiler to replace indirect calls through the pointer with
direct calls to the function it's know to point to, and then, if an
inline definition of the function is available, by inlining it. Is my
understanding correct so far?

I notice that even though the declaration of the Deg2Rad structure
member declares a function pointer, then you're redefining it as a
function. Would you be against making this two separate steps, to allow
the function have its own name?

inline int Common_Deg2Rad(double foo) { return foo/57.295; }
int (*Interface1.Deg2Rad)(double foo) = Common_Deg2Rad;
int (*Interface2.Deg2Rad)(double foo) = Common_Deg2Rad;

Would you be against allowing this new feature to be applied to all
structure members regardless of their type, rather than just function
pointers? For instance, do you think the same new syntax could be used
to specify the values of SomeData and MoreData from your example?

char *Interface.SomeData = "Hello";
double complex Interface.MoreData = I;

If your goal is to enforce the struct member to be initialized to a
particular value so that the compiler knows it without reading it from
memory, is there a point in keeping it in memory anyway? If the
declarations make it obvious to the compiler that the Deg2Rad member of
any Interface object points to the same function, why would I write code
that uses the pointer inside the structure to call the function, instead
of just calling the function directly by name?

jacob navia

unread,
May 14, 2012, 5:23:52 PM5/14/12
to
Le 14/05/12 22:30, Wojtek Lerch a écrit :
> On 14-May-12 10:11 AM, jacob navia wrote:
>> This is an interface:
>>
>> typedef struct interface {
>> int (const *Deg2Rad)(double foo);
>> double (*doubleFn)(double foo);
>> char *SomeData;
>> double complex MoreData;
>> } Interface;
>>
>> Now, I want to say that the member "Deg2Fn" is the following
>> INLINE function:
>>
>> inline int Interface.Deg2Rad(double foo) { return foo/57.295; }
>
> It seems that you basically want to be able to specify that member X of
> structure Y must always be initialized to the same value in every object
> whose type is Y (or maybe just every explicitly initialized Y object).

YES.

> In this example, you want every object defined as an Interface to have
> its Deg2Rad member initialized to the address of the same function, to
> allow the compiler to replace indirect calls through the pointer with
> direct calls to the function it's know to point to, and then, if an
> inline definition of the function is available, by inlining it. Is my
> understanding correct so far?
>

YES.


> I notice that even though the declaration of the Deg2Rad structure
> member declares a function pointer, then you're redefining it as a
> function. Would you be against making this two separate steps, to allow
> the function have its own name?
>
> inline int Common_Deg2Rad(double foo) { return foo/57.295; }
> int (*Interface1.Deg2Rad)(double foo) = Common_Deg2Rad;
> int (*Interface2.Deg2Rad)(double foo) = Common_Deg2Rad;
>

Yes, that is a good idea since allows you to reduce code footprint
by sharing code between interfaces. But that is an optimization,
so to speak.

> Would you be against allowing this new feature to be applied to all
> structure members regardless of their type, rather than just function
> pointers?

My main problem is inlining function calls to function pointers
within structures. It could have other uses for immediate data,
but in the context of C those uses are not so crucial, since
if you want always the integer 2 to be at the first position of
the structure you can initialize it to that without any real
problem. Inline calls are different because they NEED to be
known to the compiler.

If you setup your init procedure for the interface to assign the data
fields to some specific values, it surely takes some time (minimal) but
it is doable. But you CAN'T inline a non-inlined function at run-time.
That is a huge difference.

But of course I wouldn't oppose it in a more general solution.


> For instance, do you think the same new syntax could be used
> to specify the values of SomeData and MoreData from your example?
>

That would be a more general solution, yes. I tend to try to
ask the smallest solution possible to avoid getting people angry
at me.

> char *Interface.SomeData = "Hello";
> double complex Interface.MoreData = I;
>
> If your goal is to enforce the struct member to be initialized to a
> particular value so that the compiler knows it without reading it from
> memory, is there a point in keeping it in memory anyway? If the
> declarations make it obvious to the compiler that the Deg2Rad member of
> any Interface object points to the same function, why would I write code
> that uses the pointer inside the structure to call the function, instead
> of just calling the function directly by name?
>

Obviously because you do NOT want ALL function pointers in a structure
inlined!

Normally you have in an interface some functions that are just
covers (like macros). For instance I could have defined

#define Deg2rad(arg) (arg/52.295)

but an inline function gets better type checking as everyone knows.

So, it is better to use inline functions. Now, why put them in an
interface?

1) Documentation and code structuring.
2) Avoiding name pollution: the function is not part of the
global namespace (the only one in C).

There was a proposal to incorporate C++ syntax to define this:

typedef struct interface{
double (*Deg2Rad)(double arg) { return arg/57.295;}
double foo;
} Interface;

Problem is:

Are the OTHER members of the structure that is not yet fully
defined available ? I do not know the answer in the context
of C, and I wouldn't want to add a construct that REQUIRES a two
pass compiler into the language. lcc-win is a one pass
compiler, for instance, and it is very fast.

The syntax

double Interface.Deg2Rad(double arg) {return arg/57.295;}

has the advantage of avoiding those questions and keeping the
compiler one pass.

But it could be OK to add the C++ syntax if we decide that
struct members further DOWN the definition are just not available!
That would avoid requiring two passes. But then, we would have
the same syntax as C++ with quite different semantics, what would
build a big gotcha! for C++ people that use this.

A completely different syntax is better than having all those problems
in my opinion.

Thanks for your answer

jacob

Wojtek Lerch

unread,
May 14, 2012, 11:38:28 PM5/14/12
to
On 14/05/2012 5:23 PM, jacob navia wrote:
> Le 14/05/12 22:30, Wojtek Lerch a écrit :
...
>> Would you be against allowing this new feature to be applied to all
>> structure members regardless of their type, rather than just function
>> pointers?
>
> My main problem is inlining function calls to function pointers
> within structures. It could have other uses for immediate data,
> but in the context of C those uses are not so crucial, since
> if you want always the integer 2 to be at the first position of
> the structure you can initialize it to that without any real
> problem. Inline calls are different because they NEED to be
> known to the compiler.

Still, if the compiler *knew* that it's 2 in all instances of the
structure, it could "inline" it in the sense that it would become a
compile-time constant, sometimes allowing the compiler to completely
throw away whole branches of conditionals, etc.

>> For instance, do you think the same new syntax could be used
>> to specify the values of SomeData and MoreData from your example?
>>
>
> That would be a more general solution, yes. I tend to try to
> ask the smallest solution possible to avoid getting people angry
> at me.

I can think of a few ways you could try that might work better... In
this case, I think your minimalism hurts your proposal, because it
reduces its potential benefits without really reducing the complexity or
the size of the language change.

>> char *Interface.SomeData = "Hello";
>> double complex Interface.MoreData = I;
>>
>> If your goal is to enforce the struct member to be initialized to a
>> particular value so that the compiler knows it without reading it from
>> memory, is there a point in keeping it in memory anyway? If the
>> declarations make it obvious to the compiler that the Deg2Rad member of
>> any Interface object points to the same function, why would I write code
>> that uses the pointer inside the structure to call the function, instead
>> of just calling the function directly by name?
>
> Obviously because you do NOT want ALL function pointers in a structure
> inlined!

Excuse me? Are you saying that I would want to use the pointer in the
structure instead of directly calling Common_Deg2Rad() in those cases
when I do *not* want the call inlined? And that that's obvious???

Wasn't the whole purpose of your proposal to ensure that an indirect
call through the pointer could get inlined just like a direct call would?

Or did you just misunderstand my question? Let me try again:

Given your struct definition and my

inline int Common_Deg2Rad(double foo) { return foo/57.295; }
int (*Interface1.Deg2Rad)(double foo) = Common_Deg2Rad;

what reasons would one have to use the expression

z = p->Deg2Rad( x );

instead of

z = Common_Deg2Rad( x );

It wouldn't be because I don't want the second one inlined, would it?

> Normally you have in an interface some functions that are just
> covers (like macros). For instance I could have defined
>
> #define Deg2rad(arg) (arg/52.295)
>
> but an inline function gets better type checking as everyone knows.
>
> So, it is better to use inline functions. Now, why put them in an
> interface?

First of all, what is an interface? And before I can think of ways of
putting inline functions in it, how do you put macros in it? Or regular
functions?

> 1) Documentation and code structuring.
> 2) Avoiding name pollution: the function is not part of the
> global namespace (the only one in C).
>
> There was a proposal to incorporate C++ syntax to define this:
>
> typedef struct interface{
> double (*Deg2Rad)(double arg) { return arg/57.295;}
> double foo;
> } Interface;

This is not valid C++, is it? Did you mean

typedef struct interface{
double Deg2Rad(double arg) { return arg/57.295;}
double foo;
} Interface;

If so, then this is completely different from what I thought you wanted
to propose. In this C++ example, "Deg2Rad" is not a pointer sitting in
the structure. It's just a regular function with a funny name
(interface::Deg2Rad) and an implicit extra parameter (struct interface
*this) that needs to be passed to the function using a funny syntax that
looks like the syntax of an indirect call through a pointer sitting
inside the structure. The reason the compiler knows that a call such as
p->Deg2Rad(45) calls that particular function, and that it can therefore
inline it, is not because it knows what function the pointer member in
the structure points to -- it's because there no pointer there, and the
expression directly names the function it calls.

> Problem is:
>
> Are the OTHER members of the structure that is not yet fully
> defined available ? I do not know the answer in the context
> of C, and I wouldn't want to add a construct that REQUIRES a two
> pass compiler into the language. lcc-win is a one pass
> compiler, for instance, and it is very fast.
>
> The syntax
>
> double Interface.Deg2Rad(double arg) {return arg/57.295;}
>
> has the advantage of avoiding those questions and keeping the
> compiler one pass.

I suspect this syntax would also have many disadvantages, but I would
have to see a better description of the semantics first. The devil is
in the detail.

> But it could be OK to add the C++ syntax if we decide that
> struct members further DOWN the definition are just not available!
> That would avoid requiring two passes. But then, we would have
> the same syntax as C++ with quite different semantics, what would
> build a big gotcha! for C++ people that use this.

No argument there. Identical syntax with different semantics would be a
disaster.

> A completely different syntax is better than having all those problems
> in my opinion.

Agreed. A detailed description of the semantics that you want the new
syntax to have would be helpful though. A description that is too
detailed and explains obvious things is not going to hurt your case as
much as an example of the syntax and a vague comment implying that the
semantics that you have in mind are obvious. Obviously, they're obvious
to you; but the rest of us prefer to read a written explanation instead
of trying to read your mind.

Martin Shobe

unread,
May 15, 2012, 2:33:37 PM5/15/12
to
Wojtek Lerch wrote:

> On 14/05/2012 5:23 PM, jacob navia wrote:
>> Le 14/05/12 22:30, Wojtek Lerch a écrit :
[snip]
>> 1) Documentation and code structuring.
>> 2) Avoiding name pollution: the function is not part of the
>> global namespace (the only one in C).
>>
>> There was a proposal to incorporate C++ syntax to define this:
>>
>> typedef struct interface{
>> double (*Deg2Rad)(double arg) { return arg/57.295;}
>> double foo;
>> } Interface;
>
> This is not valid C++, is it? Did you mean
>
> typedef struct interface{
> double Deg2Rad(double arg) { return arg/57.295;}
> double foo;
> } Interface;
>
> If so, then this is completely different from what I thought you wanted
> to propose. In this C++ example, "Deg2Rad" is not a pointer sitting in
> the structure. It's just a regular function with a funny name
> (interface::Deg2Rad) and an implicit extra parameter (struct interface
> *this) that needs to be passed to the function using a funny syntax that
> looks like the syntax of an indirect call through a pointer sitting
> inside the structure. The reason the compiler knows that a call such as
> p->Deg2Rad(45) calls that particular function, and that it can therefore
> inline it, is not because it knows what function the pointer member in
> the structure points to -- it's because there no pointer there, and the
> expression directly names the function it calls.

It also has the inline semantics that allow for it to be defined in
multiple translation units without issues. But that' s not quite what I
was thinking of when I said it. What I was thinking of would have the
semantics of C++'s

struct Interface
{
static double Deg2Rad(double arg) { return arg / 57.295; }
};

Since I hadn't proposed adding the scope resolution operator, it would
only be accessable via an object, or a null pointer of the appropriate
type.

Obviously, it's not a serious proposal since it would be incompatible
with C++ [as you noted later].

[snip]

Martin Shobe

0 new messages