Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #147593 > unrolled thread
| Started by | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| First post | 2019-11-04 22:55 -0800 |
| Last post | 2019-11-09 23:22 -0800 |
| Articles | 20 on this page of 65 — 12 participants |
Back to article view | Back to comp.lang.c
Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-04 22:55 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 08:12 +0100
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-05 03:52 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 13:12 +0100
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-05 04:24 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 13:33 +0100
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-05 04:57 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 14:08 +0100
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-05 05:21 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 14:27 +0100
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-05 05:42 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 14:51 +0100
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-05 14:49 +0000
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 15:53 +0100
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-05 15:59 +0000
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 17:11 +0100
Re: Is this kosher wrt Generic? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-11-05 09:19 -0800
Re: Is this kosher wrt Generic? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-11-05 07:00 -0800
Re: Is this kosher wrt Generic? David Brown <david.brown@hesbynett.no> - 2019-11-05 16:30 +0100
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 15:31 +0100
Re: Is this kosher wrt Generic? Ian Collins <ian-news@hotmail.com> - 2019-11-06 10:34 +1300
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-05 22:16 +0000
Re: Is this kosher wrt Generic? Ian Collins <ian-news@hotmail.com> - 2019-11-06 11:34 +1300
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-05 23:12 +0000
Re: Is this kosher wrt Generic? Ian Collins <ian-news@hotmail.com> - 2019-11-06 12:29 +1300
Re: Is this kosher wrt Generic? David Brown <david.brown@hesbynett.no> - 2019-11-06 10:17 +0100
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-06 10:56 +0100
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-06 10:02 +0100
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-06 10:43 +0000
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-06 04:56 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-06 14:05 +0100
Re: Is this kosher wrt Generic? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-11-08 21:03 -0800
Re: Is this kosher wrt Generic? Ian Collins <ian-news@hotmail.com> - 2019-11-10 08:45 +1300
Re: Is this kosher wrt Generic? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-11-28 16:35 -0800
Re: Is this kosher wrt Generic? David Brown <david.brown@hesbynett.no> - 2019-11-29 12:41 +0100
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-29 04:08 -0800
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-29 13:01 +0000
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-29 06:43 -0800
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-29 17:31 +0000
Re: Is this kosher wrt Generic? David Brown <david.brown@hesbynett.no> - 2019-11-29 14:31 +0100
Re: Is this kosher wrt Generic? Öö Tiib <ootiib@hot.ee> - 2019-11-30 13:16 -0800
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-12-02 03:31 -0800
Re: Is this kosher wrt Generic? Öö Tiib <ootiib@hot.ee> - 2019-12-02 23:30 -0800
Re: Is this kosher wrt Generic? Ian Collins <ian-news@hotmail.com> - 2019-12-01 12:10 +1300
Re: Is this kosher wrt Generic? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2020-01-11 09:35 -0800
Re: Is this kosher wrt Generic? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-11-05 22:49 +0000
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-05 05:12 -0800
Re: Is this kosher wrt Generic? Bonita Montero <Bonita.Montero@gmail.com> - 2019-11-05 14:20 +0100
Re: Is this kosher wrt Generic? guinness.tony@gmail.com - 2019-11-05 16:19 -0800
Re: Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-06 00:06 -0800
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-05 03:19 -0800
Re: Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-05 22:38 -0800
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-06 04:50 -0800
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-06 05:32 -0800
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-06 05:56 -0800
Re: Is this kosher wrt Generic? Bart <bc@freeuk.com> - 2019-11-06 14:26 +0000
Re: Is this kosher wrt Generic? Thiago Adams <thiago.adams@gmail.com> - 2019-11-06 09:04 -0800
Re: Is this kosher wrt Generic? David Brown <david.brown@hesbynett.no> - 2019-11-06 22:45 +0100
Re: Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-29 14:35 -0800
Re: Is this kosher wrt Generic? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-29 23:23 +0000
Re: Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-29 19:08 -0800
Re: Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-29 19:12 -0800
Re: Is this kosher wrt Generic? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-30 10:44 +0000
Re: Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-09 23:21 -0800
Re: Is this kosher wrt Generic? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-11-09 23:22 -0800
Page 3 of 4 — ← Prev page 1 2 [3] 4 Next page →
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-11-30 13:16 -0800 |
| Message-ID | <e28d302a-5fb7-4a9e-9686-637394f75dfa@googlegroups.com> |
| In reply to | #148280 |
On Friday, 29 November 2019 14:09:10 UTC+2, Thiago Adams wrote:
> On Friday, November 29, 2019 at 8:41:29 AM UTC-3, David Brown wrote:
> ...
> > Thus you can make classes, use RAII for resource control, have
> > unique_ptr's for memory handling, store data in std::vectors, work with
> > std::string - all without ever writing or seeing the word "template", or
> > understanding rvalue references, or getting your head around
> > "enable_if". Many of C++'s more complex features exist primarily so
> > that the standard library (and other libraries) can be written, so that
> > application code writers can get efficient code without having to
> > understand these complexities.
>
> Recently, a beginner colleague of mine call me saying:
>
> "Please look at this error..."
>
> The error was really big.
>
> I don't remember the details, but we had an object used included
> in some container.
>
> Like this:
>
> class X {
> int i;
> };
>
>
> int main() {
> std::vector<X> v;
> X x;
> v.push_back(x);
> }
>
> and he was adding a new member at X.
>
> class Y {int i;};
>
> class X {
> unique_ptr<Y> sp; // <- Like this
> int i;
> };
>
> Then the program stop to compile.
Makes sense, std::unique_ptr is not copyable (but is movable)
and so a struct containing it can't be copied (but can be
moved) into vector.
Demo: <http://coliru.stacked-crooked.com/a/14ad05993d274ead>
Other option is to add a copy constructor but then also rest
of The Five (plus default constructor for X x;) need to be
added manually to X.
> If you put this example online (which is much smaller than the real
> case) we have these errors:
True. What you suggest how these errors should be laid out?
I would prefer:
Who said that you can push_back non-copyable stuff into
std::vector by value, you morons, like that "v.push_back(x);"?
May be in few years. I would especially like ad hominems and
insults in diagnostics to get into correct mood of using the tool.
> As we can see, just adding a unique_ptr give us an error that requires
> a lot of knowledge about the language to fix it, or at least, understand
> why it is not working.
> He was not trying to use advanced c++ features.
Yes, C++ is decent tool but no way nice, simple or forgiving to use.
Who wants nice tool should perhaps take Rust, Swift or Kotlin.
Trouble is that Rust is in kindergarten, Swift is fruit-specific
and Kotlin runs on Oracle's runtime but may be in few years. ;)
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-12-02 03:31 -0800 |
| Message-ID | <cd80da64-d663-4525-8dfa-1cb48eeb1f65@googlegroups.com> |
| In reply to | #148312 |
On Saturday, November 30, 2019 at 6:16:42 PM UTC-3, Öö Tiib wrote:
> On Friday, 29 November 2019 14:09:10 UTC+2, Thiago Adams wrote:
> > On Friday, November 29, 2019 at 8:41:29 AM UTC-3, David Brown wrote:
> > ...
> > > Thus you can make classes, use RAII for resource control, have
> > > unique_ptr's for memory handling, store data in std::vectors, work with
> > > std::string - all without ever writing or seeing the word "template", or
> > > understanding rvalue references, or getting your head around
> > > "enable_if". Many of C++'s more complex features exist primarily so
> > > that the standard library (and other libraries) can be written, so that
> > > application code writers can get efficient code without having to
> > > understand these complexities.
> >
> > Recently, a beginner colleague of mine call me saying:
> >
> > "Please look at this error..."
> >
> > The error was really big.
> >
> > I don't remember the details, but we had an object used included
> > in some container.
> >
> > Like this:
> >
> > class X {
> > int i;
> > };
> >
> >
> > int main() {
> > std::vector<X> v;
> > X x;
> > v.push_back(x);
> > }
> >
> > and he was adding a new member at X.
> >
> > class Y {int i;};
> >
> > class X {
> > unique_ptr<Y> sp; // <- Like this
> > int i;
> > };
> >
> > Then the program stop to compile.
>
> Makes sense, std::unique_ptr is not copyable (but is movable)
> and so a struct containing it can't be copied (but can be
> moved) into vector.
> Demo: <http://coliru.stacked-crooked.com/a/14ad05993d274ead>
> Other option is to add a copy constructor but then also rest
> of The Five (plus default constructor for X x;) need to be
> added manually to X.
>
> > If you put this example online (which is much smaller than the real
> > case) we have these errors:
>
> True. What you suggest how these errors should be laid out?
>
> I would prefer:
> Who said that you can push_back non-copyable stuff into
> std::vector by value, you morons, like that "v.push_back(x);"?
When push_back was written the copy ctor was ok. The programmer wasn't
a moron.
When a new feature was required, the code needed some changes.
The programmer that is making the change is also correct
because in this case, unique_ptr was a good choice of use.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-02 23:30 -0800 |
| Message-ID | <d9c945ae-a00f-4d5b-a082-fb34021d73b6@googlegroups.com> |
| In reply to | #148341 |
On Monday, 2 December 2019 13:32:06 UTC+2, Thiago Adams wrote:
> On Saturday, November 30, 2019 at 6:16:42 PM UTC-3, Öö Tiib wrote:
> > On Friday, 29 November 2019 14:09:10 UTC+2, Thiago Adams wrote:
> > > On Friday, November 29, 2019 at 8:41:29 AM UTC-3, David Brown wrote:
> > > ...
> > > > Thus you can make classes, use RAII for resource control, have
> > > > unique_ptr's for memory handling, store data in std::vectors, work with
> > > > std::string - all without ever writing or seeing the word "template", or
> > > > understanding rvalue references, or getting your head around
> > > > "enable_if". Many of C++'s more complex features exist primarily so
> > > > that the standard library (and other libraries) can be written, so that
> > > > application code writers can get efficient code without having to
> > > > understand these complexities.
> > >
> > > Recently, a beginner colleague of mine call me saying:
> > >
> > > "Please look at this error..."
> > >
> > > The error was really big.
> > >
> > > I don't remember the details, but we had an object used included
> > > in some container.
> > >
> > > Like this:
> > >
> > > class X {
> > > int i;
> > > };
> > >
> > >
> > > int main() {
> > > std::vector<X> v;
> > > X x;
> > > v.push_back(x);
> > > }
> > >
> > > and he was adding a new member at X.
> > >
> > > class Y {int i;};
> > >
> > > class X {
> > > unique_ptr<Y> sp; // <- Like this
> > > int i;
> > > };
> > >
> > > Then the program stop to compile.
> >
> > Makes sense, std::unique_ptr is not copyable (but is movable)
> > and so a struct containing it can't be copied (but can be
> > moved) into vector.
> > Demo: <http://coliru.stacked-crooked.com/a/14ad05993d274ead>
> > Other option is to add a copy constructor but then also rest
> > of The Five (plus default constructor for X x;) need to be
> > added manually to X.
> >
> > > If you put this example online (which is much smaller than the real
> > > case) we have these errors:
> >
> > True. What you suggest how these errors should be laid out?
> >
> > I would prefer:
> > Who said that you can push_back non-copyable stuff into
> > std::vector by value, you morons, like that "v.push_back(x);"?
>
> When push_back was written the copy ctor was ok. The programmer wasn't
> a moron.
It does not matter. From C++ compiler I would like patronizing, mocking
and unjustly insulting tone of diagnostics to get into correct mood
of using the very programming language. It is pretty good programming
language but it is designed to be very novice-unfriendly. So such
disrespectful attitude would fit well into that situation and even
perhaps reduce confusion.
> When a new feature was required, the code needed some changes.
> The programmer that is making the change is also correct
> because in this case, unique_ptr was a good choice of use.
Yes, unique_ptr is great. I replaced all boost::scoped_ptr and
several boost::shared_ptr with it ASAP when it come out. A raw
pointer at that place would cause defective program to compile.
The unique_ptr does not let it to happen but before one does
not study the nuances of its usage it will be just a pain of
different nature.
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2019-12-01 12:10 +1300 |
| Message-ID | <h4gb6qFft80U1@mid.individual.net> |
| In reply to | #148205 |
On 29/11/2019 13:35, Tim Rentsch wrote: > Ian Collins <ian-news@hotmail.com> writes: > >> On 09/11/2019 18:03, Tim Rentsch wrote: >> >>> Ian Collins <ian-news@hotmail.com> writes: >>> >>>> On 06/11/2019 01:57, Thiago Adams wrote: >>>> >>>>> C is dangerous but it is simple. When you know the tool you >>>>> know exactly what the compiler is doing and you know from a long >>>>> time what is important to do and check. How to deal with the >>>>> details. >>>>> >>>>> C++ is complex and nobody knows happens under the hood. This is why >>>>> site that shows the compiler output are so useful nowadays for C++ >>>>> community. >>>>> >>>>> C is not perfect and C++ is not so bad. Personally I wish I could >>>>> select some features from both and add some extra ones. >>>>> This is why I created my own C front end. >>>> >>>> The complexity in a programming problem is a constant. You can solve >>>> it in the C way with a large number of simple steps, which introduces >>>> extra complexity in making sure they all work together. You can solve >>>> it with fewer step in a higher level language, which introduces extra >>>> complexity to the language. The overall complexity remains constant. >>> >>> Mother Goose comes to comp.lang.c. >> >> I assume by your recent tone that you have been smoking something... > > Ahh, and here we have another ad hominem remark. When one > doesn't have either the facts or the law on their side, all > that's left is attacking the character of one's opponent. Pot, kettle? >> Take a concrete example: resource management. >> >> In C resource management is transparent but manual, the programmer has >> to track what has been allocated and know when to free it. This, >> along with the opportunity for error, gets quite complex when a >> resource is shared, especially between threads. >> >> In C++, adding some extra complexity in the language (constructors and >> automatic object destruction) removes the complexity and the >> opportunities for error from the user code. >> >> The code is still doing the same work and may well compile down to >> equivalent assembler. The overall complexity remains constant. > > Two problems: this assumes complexity is a scalar, which it > isn't, and that it is simply additive, which it also isn't. In the example I mentioned, the complexity could be a measure of the generated object code required to solve the problem. If C and C++ generate the same or very similar object code, it's fair to say the code is doing the same work and to compare the complexity of (and opportunities for error in) the source code. > Furthermore it ignores the cost of all the other complexity in > C++ that must be paid whether the program needs it or not. C++ has always had the philosophy of if you don't need it, you don't pay for it. > Very few programs, if any, need all of the complex features that C++ > provides. And very few, if any, use all of the complex features that C++ provides. > I think it was Tony Hoare who pointed out that a > programming language shouldn't the union of all features needed > by any program, but rather the intersection of features needed > in every program. Otherwise essentially every program is paying > a complexity cost for some unneeded features. David has already said all I would have said in replay to this. -- Ian.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2020-01-11 09:35 -0800 |
| Message-ID | <864kx13ngm.fsf@linuxsc.com> |
| In reply to | #148315 |
Ian Collins <ian-news@hotmail.com> writes: > On 29/11/2019 13:35, Tim Rentsch wrote: > >> Ian Collins <ian-news@hotmail.com> writes: >> >>> On 09/11/2019 18:03, Tim Rentsch wrote: >>> >>>> Ian Collins <ian-news@hotmail.com> writes: >>>> >>>>> On 06/11/2019 01:57, Thiago Adams wrote: >>>>> >>>>>> C is dangerous but it is simple. When you know the tool you >>>>>> know exactly what the compiler is doing and you know from a long >>>>>> time what is important to do and check. How to deal with the >>>>>> details. >>>>>> >>>>>> C++ is complex and nobody knows happens under the hood. This is why >>>>>> site that shows the compiler output are so useful nowadays for C++ >>>>>> community. >>>>>> >>>>>> C is not perfect and C++ is not so bad. Personally I wish I could >>>>>> select some features from both and add some extra ones. >>>>>> This is why I created my own C front end. >>>>> >>>>> The complexity in a programming problem is a constant. You can solve >>>>> it in the C way with a large number of simple steps, which introduces >>>>> extra complexity in making sure they all work together. You can solve >>>>> it with fewer step in a higher level language, which introduces extra >>>>> complexity to the language. The overall complexity remains constant. >>>> >>>> Mother Goose comes to comp.lang.c. >>> >>> I assume by your recent tone that you have been smoking something... >> >> Ahh, and here we have another ad hominem remark. When one >> doesn't have either the facts or the law on their side, all >> that's left is attacking the character of one's opponent. > > Pot, kettle? None of my comments here have been ad hominem remarks. I have said things about what you have said, but nothing of what I have said has been about you as opposed to what you have said. >>> Take a concrete example: resource management. >>> >>> In C resource management is transparent but manual, the programmer has >>> to track what has been allocated and know when to free it. This, >>> along with the opportunity for error, gets quite complex when a >>> resource is shared, especially between threads. >>> >>> In C++, adding some extra complexity in the language (constructors and >>> automatic object destruction) removes the complexity and the >>> opportunities for error from the user code. >>> >>> The code is still doing the same work and may well compile down to >>> equivalent assembler. The overall complexity remains constant. >> >> Two problems: this assumes complexity is a scalar, which it >> isn't, and that it is simply additive, which it also isn't. > > In the example I mentioned, the complexity could be a measure of the > generated object code required to solve the problem. If C and C++ > generate the same or very similar object code, it's fair to say the > code is doing the same work and to compare the complexity of (and > opportunities for error in) the source code. If you think the complexity of a programming _problem_ is constant, then measuring generated object code cannot be a valid complexity metric. >> Furthermore it ignores the cost of all the other complexity in >> C++ that must be paid whether the program needs it or not. > > C++ has always had the philosophy of if you don't need it, you don't > pay for it. Having a philosophy doesn't mean it has been achieved. The idea that you don't need to know about language features you don't use has long been debunked. >> Very few programs, if any, need all of the complex features that C++ >> provides. > > And very few, if any, use all of the complex features that C++ provides. See above. >> I think it was Tony Hoare who pointed out that a >> programming language shouldn't the union of all features needed >> by any program, but rather the intersection of features needed >> in every program. Otherwise essentially every program is paying >> a complexity cost for some unneeded features. > > David has already said all I would have said in replay to this. If you mean David Brown, I didn't see his comments.
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2019-11-05 22:49 +0000 |
| Message-ID | <slrnqs3v4f.cdo.grahn+nntp@frailea.sa.invalid> |
| In reply to | #147601 |
On Tue, 2019-11-05, Thiago Adams wrote: ... > When I watch C++ conferences like cppcon, people are talking about > C++ performance problems or C++ pitfalls or about new features that > will bring new performance problem and pitfalls for the next year. Don't judge actual C++ programming based on what you see in conference videos. Most of us are concerned with getting work done, and don't actively look for trouble. Talking about that would make for a very boring conference ... /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-11-05 05:12 -0800 |
| Message-ID | <d54e3fed-01a2-449b-a1c8-d7a16678de8c@googlegroups.com> |
| In reply to | #147600 |
On Tuesday, November 5, 2019 at 10:33:50 AM UTC-2, Bonita Montero wrote: > >> The simplicity-paradigma o C isn't modern. > > > In my view, simplicity is always modern. > > When a language has a simplicity that leads to error-prone programming > and implementing a problem takes much more work than in other languages, > this language isn't appropriate. > > > "Complexity sells better" works until some point. C++ has > > passed this point and it complexity is playing against it. > > C++ is of course not appropriate for beginners, but you > don't need to be a top-developer to handle toe language. What is interesting, is that you are posting in a c group: I believe you have some felling like: - These programmers use C because they are ignorant about C++. if they know how C++ is good probably they would not use C. - These programmers use C because they are not clever enough to learn C++. - These programmers stopped in some point in time, and never updated their knowledge about C++. But also: - If my assumptions are not true (I need to check) why someone still using C? Maybe C is good? - C is fast. - C is simple. :D
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2019-11-05 14:20 +0100 |
| Message-ID | <qprsv8$lsh$1@news.albasani.net> |
| In reply to | #147603 |
> - C is fast. > - C is simple. The language is simple, but it isn't simple to handle complex problems in C because of the simplicity of C.
[toc] | [prev] | [next] | [standalone]
| From | guinness.tony@gmail.com |
|---|---|
| Date | 2019-11-05 16:19 -0800 |
| Message-ID | <f9ff4b8a-ae97-4568-afee-89031802d0a6@googlegroups.com> |
| In reply to | #147594 |
On Tuesday, 5 November 2019 08:12:08 UTC+1, Bonita Montero wrote: > Forget generic programming in C; that't ultimatively ugly! The non-word “ultimatively” that you invented is the only ugly thing here.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2019-11-06 00:06 -0800 |
| Message-ID | <qptuu5$pt6$4@gioia.aioe.org> |
| In reply to | #147594 |
On 11/4/2019 11:12 PM, Bonita Montero wrote: > Forget generic programming in C; that't ultimatively ugly! Its not the most attractive being out there for sure! Although, for some very strange reason, you kind of remind me of JG over on sci.math. Humm... Sorry for that. Btw, please, for the love of God, try to give a proper attribution?
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-11-05 03:19 -0800 |
| Message-ID | <c241e694-e1fb-4c93-aac6-8a3eaf8080b5@googlegroups.com> |
| In reply to | #147593 |
On Tuesday, November 5, 2019 at 4:55:58 AM UTC-2, Chris M. Thomasson wrote:
> An experiment:
> _________________________________
> #include <stdio.h>
>
>
> struct foo_0
> {
> unsigned int blah0;
> };
>
> struct foo_1
> {
> unsigned int blah0;
> unsigned int blah1;
> };
>
>
> void foo_0(struct foo_0* self, int a, int b)
> {
> printf("foo_0(%p, blah0: %u, %u, %u)\n",
> (void*)self, self->blah0, a, b);
> }
>
> void foo_1(struct foo_1* self, int a, int b)
> {
> printf("foo_1(%p, blah0: %u, blah1: %u, %u, %u)\n",
> (void*)self, self->blah0, self->blah1, a, b);
> }
>
>
> #define foo(a, ...) \
> (_Generic((a), \
> struct foo_0*: foo_0, \
> struct foo_1*: foo_1 \
> )((a), __VA_ARGS__))
>
>
> int main(void)
> {
> struct foo_0 f0 = { 1 };
> struct foo_1 f1 = { 2, 3 };
>
> foo(&f0, 4, 5); // Calls foo_0
> foo(&f1, 4, 5); // Calls foo_1
>
> return 0;
> }
> _________________________________
>
> foo seems pretty nice to me. :^)
The only thing I don't like is that we need to add all types in
one place instead of being able to declare separately.
This makes difficult to add new types. For instance, to add food_3.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2019-11-05 22:38 -0800 |
| Message-ID | <qptpoa$6a4$1@gioia.aioe.org> |
| In reply to | #147596 |
On 11/5/2019 3:19 AM, Thiago Adams wrote:
> On Tuesday, November 5, 2019 at 4:55:58 AM UTC-2, Chris M. Thomasson wrote:
>> An experiment:
>> _________________________________
[...]
>> #define foo(a, ...) \
>> (_Generic((a), \
>> struct foo_0*: foo_0, \
>> struct foo_1*: foo_1 \
>> )((a), __VA_ARGS__))
>>
>>
>> int main(void)
>> {
>> struct foo_0 f0 = { 1 };
>> struct foo_1 f1 = { 2, 3 };
>>
>> foo(&f0, 4, 5); // Calls foo_0
>> foo(&f1, 4, 5); // Calls foo_1
>>
>> return 0;
>> }
>> _________________________________
>>
>> foo seems pretty nice to me. :^)
> The only thing I don't like is that we need to add all types in
> one place instead of being able to declare separately. > This makes difficult to add new types. For instance, to add food_3.
Yeah. Its not very convenient. To add in a new type:
_______________________________
#include <stdio.h>
struct foo_0
{
unsigned int blah0;
};
struct foo_1
{
unsigned int blah0;
unsigned int blah1;
};
void foo_0(struct foo_0* self, int a, int b)
{
printf("foo_0(%p, blah0: %u, %u, %u)\n",
(void*)self, self->blah0, a, b);
}
void foo_1(struct foo_1* self, int a, int b)
{
printf("foo_1(%p, blah0: %u, blah1: %u, %u, %u)\n",
(void*)self, self->blah0, self->blah1, a, b);
}
struct new_type
{
double v[3];
};
void foo_new_type(struct new_type* self, double a)
{
printf("foo_new_type(%p)\n",
(void*)self);
}
#define foo(a, ...) \
(_Generic((a), \
struct foo_0*: foo_0, \
struct foo_1*: foo_1, \
struct new_type*: foo_new_type \
)((a), __VA_ARGS__))
int main(void)
{
struct foo_0 f0 = { 1 };
struct foo_1 f1 = { 2, 3 };
foo(&f0, 4, 5); // Calls foo_0
foo(&f1, 4, 5); // Calls foo_1
struct new_type nt = { { -1., 1., 0. } };
foo(&nt, 3.14); // Calls foo_new_type
return 0;
}
_______________________________
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-11-06 04:50 -0800 |
| Message-ID | <8f6ba3a5-3385-45f8-bfc6-342f6cbd54d4@googlegroups.com> |
| In reply to | #147649 |
On Wednesday, November 6, 2019 at 3:38:13 AM UTC-3, Chris M. Thomasson wrote:
> On 11/5/2019 3:19 AM, Thiago Adams wrote:
> > On Tuesday, November 5, 2019 at 4:55:58 AM UTC-2, Chris M. Thomasson wrote:
> >> An experiment:
> >> _________________________________
> [...]
> >> #define foo(a, ...) \
> >> (_Generic((a), \
> >> struct foo_0*: foo_0, \
> >> struct foo_1*: foo_1 \
> >> )((a), __VA_ARGS__))
> >>
> >>
> >> int main(void)
> >> {
> >> struct foo_0 f0 = { 1 };
> >> struct foo_1 f1 = { 2, 3 };
> >>
> >> foo(&f0, 4, 5); // Calls foo_0
> >> foo(&f1, 4, 5); // Calls foo_1
> >>
> >> return 0;
> >> }
> >> _________________________________
> >>
> >> foo seems pretty nice to me. :^)
>
> > The only thing I don't like is that we need to add all types in
> > one place instead of being able to declare separately. > This makes difficult to add new types. For instance, to add food_3.
>
> Yeah. Its not very convenient. To add in a new type:
> _______________________________
> #include <stdio.h>
>
>
> struct foo_0
> {
> unsigned int blah0;
> };
>
> struct foo_1
> {
> unsigned int blah0;
> unsigned int blah1;
> };
>
>
> void foo_0(struct foo_0* self, int a, int b)
> {
> printf("foo_0(%p, blah0: %u, %u, %u)\n",
> (void*)self, self->blah0, a, b);
> }
>
> void foo_1(struct foo_1* self, int a, int b)
> {
> printf("foo_1(%p, blah0: %u, blah1: %u, %u, %u)\n",
> (void*)self, self->blah0, self->blah1, a, b);
> }
>
>
>
> struct new_type
> {
> double v[3];
> };
>
> void foo_new_type(struct new_type* self, double a)
> {
> printf("foo_new_type(%p)\n",
> (void*)self);
> }
>
> #define foo(a, ...) \
> (_Generic((a), \
> struct foo_0*: foo_0, \
> struct foo_1*: foo_1, \
> struct new_type*: foo_new_type \
> )((a), __VA_ARGS__))
>
>
> int main(void)
> {
> struct foo_0 f0 = { 1 };
> struct foo_1 f1 = { 2, 3 };
>
> foo(&f0, 4, 5); // Calls foo_0
> foo(&f1, 4, 5); // Calls foo_1
>
> struct new_type nt = { { -1., 1., 0. } };
>
> foo(&nt, 3.14); // Calls foo_new_type
>
> return 0;
> }
> _______________________________
In the standard we have the generic function sqrt .
It is implemented with _Generic.
Now imagine we want to add a new type that also
implements sqrt, for instance big int type.
In this we would have to change the code that is
provided by the standard to include the new type?
(this is the problem)
Alternatives?
One workaround is to build the final _Generic expression,
using parts of different sources (libs)
Something like:
#include <stdio.h>
//Lib 1
struct foo_0
{
unsigned int blah0;
};
struct foo_1
{
unsigned int blah0;
unsigned int blah1;
};
void foo_0(struct foo_0* self, int a, int b)
{
printf("foo_0(%p, blah0: %u, %u, %u)\n",
(void*)self, self->blah0, a, b);
}
void foo_1(struct foo_1* self, int a, int b)
{
printf("foo_1(%p, blah0: %u, blah1: %u, %u, %u)\n",
(void*)self, self->blah0, self->blah1, a, b);
}
#define LIB1_FOO_TYPES \
struct foo_0*: foo_0, \
struct foo_1*: foo_1
//Lib2
struct new_type
{
double v[3];
};
void foo_new_type(struct new_type* self, double a)
{
printf("foo_new_type(%p)\n",
(void*)self);
}
#define LIB2_FOO_TYPES \
struct new_type*: foo_new_type
// my program
#define foo(a, ...) \
(_Generic((a), \
LIB1_FOO_TYPES, \
LIB2_FOO_TYPES \
)((a), __VA_ARGS__))
int main(void)
{
struct foo_0 f0 = { 1 };
struct foo_1 f1 = { 2, 3 };
foo(&f0, 4, 5); // Calls foo_0
foo(&f1, 4, 5); // Calls foo_1
struct new_type nt = { { -1., 1., 0. } };
foo(&nt, 3.14); // Calls foo_new_type
return 0;
}
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-11-06 05:32 -0800 |
| Message-ID | <5e3b0d5e-5e2c-4acd-8111-346e859e3e51@googlegroups.com> |
| In reply to | #147664 |
On Wednesday, November 6, 2019 at 9:50:48 AM UTC-3, Thiago Adams wrote: > On Wednesday, November 6, 2019 at 3:38:13 AM UTC-3, Chris M. Thomasson wrote: > > On 11/5/2019 3:19 AM, Thiago Adams wrote: > > > On Tuesday, November 5, 2019 at 4:55:58 AM UTC-2, Chris M. Thomasson wrote: > > >> An experiment: [...] > > >> foo seems pretty nice to me. :^) > > > > > The only thing I don't like is that we need to add all types in > > > one place instead of being able to declare separately. > This makes difficult to add new types. For instance, to add food_3. > > > > Yeah. Its not very convenient. To add in a new type: [...] > In the standard we have the generic function sqrt . > It is implemented with _Generic. > Now imagine we want to add a new type that also > implements sqrt, for instance big int type. > > In this we would have to change the code that is > provided by the standard to include the new type? > (this is the problem) > > Alternatives? > [...] I already have suggested in this group a feature to build this generic selection automatically. The basic idea is to add the concept of 'function tags'. void foo_new_type(struct new_type* self, double a) : foo; Function tag is the end part ': food'; This tag can be added at the function declaration. ( The difference between this tag and C++ function overloading is that it doesn't require name mangling. ) There are two variants for this 'function tag' feature. Option 1: Any function signature Very generic where we can have the same tag for any function signature. for instance: void foo_new_type(int i) : foo; this is the way C++ is. In case you try foo_new_type(1.2f) it will print the error with all candidates. Advantage - easy to write. This model can be used in the sample (foo) because it has has different arguments for each foo. Option 2: With restrict signature. In this case we need a declaration for the 'interface' for foo. for instance, one name/concept that I would like to use for any type is destroy. All function destroy have the same signature. So the generic interface for destroy could be: void destroy(auto); and the implementation. void x_destroy(struct X* p) : destroy; the implementation must follow the destroy contract. disadvantage - have to write something else - this contract.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-11-06 05:56 -0800 |
| Message-ID | <7c6d2fae-86af-4660-932a-64bccef28b4a@googlegroups.com> |
| In reply to | #147667 |
On Wednesday, November 6, 2019 at 10:33:11 AM UTC-3, Thiago Adams wrote: > Option 2: With restrict signature. > In this case we need a declaration for the 'interface' for foo. > for instance, one name/concept that I would like to use for any > type is destroy. All function destroy have the same signature. > > So the generic interface for destroy could be: > > void destroy(auto); > > and the implementation. > > void x_destroy(struct X* p) : destroy; > > the implementation must follow the destroy contract. ... This feature with contract is similar of some C++ operator overloading. Some operators in C++ have strict contracts. For instance, the operator delete must be: void operator delete(void * p) if I change the return type for instance: void* operator delete(void * p) error: ‘operator delete’ must return type ‘void’ In my view, destroy, init, delete , new, swap, clone etc.. are 'universal operators', just like + , - 0 and they could exist by default in the C language using this feature of function tags. Not only this, but some algorithms are just a matter of composition and destroy and init are samples of that. In this case the language could generate these operators for us by composition. If we think in terms of sqrt we don't want function overloading with zero or more than one argument. In this aspect _Generic has advantages over function overloading where anything is possible.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-11-06 14:26 +0000 |
| Message-ID | <qKAwF.44683$vV6.25665@fx17.am4> |
| In reply to | #147668 |
On 06/11/2019 13:56, Thiago Adams wrote:
> On Wednesday, November 6, 2019 at 10:33:11 AM UTC-3, Thiago Adams wrote:
>> Option 2: With restrict signature.
>> In this case we need a declaration for the 'interface' for foo.
>> for instance, one name/concept that I would like to use for any
>> type is destroy. All function destroy have the same signature.
>>
>> So the generic interface for destroy could be:
>>
>> void destroy(auto);
>>
>> and the implementation.
>>
>> void x_destroy(struct X* p) : destroy;
>>
>> the implementation must follow the destroy contract.
> ...
>
>
> This feature with contract is similar of some C++ operator
> overloading.
>
> Some operators in C++ have strict contracts. For instance,
> the operator delete must be:
>
> void operator delete(void * p)
>
> if I change the return type for instance:
>
> void* operator delete(void * p)
> error: ‘operator delete’ must return type ‘void’
>
>
> In my view, destroy, init, delete , new, swap, clone etc..
> are 'universal operators', just like + , - 0 and they could exist by
> default in the C language using this feature of function tags.
>
> Not only this, but some algorithms are just a matter of
> composition and destroy and init are samples of that.
> In this case the language could generate these operators for
> us by composition.
>
> If we think in terms of sqrt we don't want function overloading
> with zero or more than one argument.
> In this aspect _Generic has advantages over function overloading
> where anything is possible.
I haven't tried function overloading (where you have to look at all
combinations of parameter and return types to choose the right function,
and there might still be ambiguities).
Class-based (or method-based) is simpler, and the choice is made on the
first parameter only. Take this example in fantasy C:
typedef struct {
void SayMyName(bart &s) {puts("Bart");}
} bart;
typedef struct {
void SayMyName(lisa &s) {puts("Lisa");}
} lisa;
bart B;
lisa L;
B.SayMyName(); // Bart
L.SayMyName(); // Lisa
bart.SayMyName(B); // Bart
lisa.SayMyName(L); // Lisa
Example shows using method-syntax based on an instance of each struct,
and also a conventional call but here you need to know the type.
(My language is supposed to be able to do this, but I've never used the
feature, and the commented-out (with "!") lines don't work ATM with the
static language, although they do with the dynamic one):
----------------------------------
record bart=
proc saymyname(bart &s) =
println "Bart"
end
end
record lisa=
proc saymyname(lisa &s) =
println "Lisa"
end
end
proc start=
var bart B
var lisa L
! B.saymyname()
! L.saymyname()
bart.saymyname(B)
lisa.saymyname(L)
end
----------------------------------
Another issue is that this scheme only works with record/struct types
where you can add a method definition to the type.
But an older idea used an 'extend type' feature to add methods not only
to existing records/structs, but to other types too. Never implemented
though.)
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-11-06 09:04 -0800 |
| Message-ID | <a44d8b27-937b-46bc-8237-5bd066745eda@googlegroups.com> |
| In reply to | #147669 |
On Wednesday, November 6, 2019 at 11:26:39 AM UTC-3, Bart wrote:
> On 06/11/2019 13:56, Thiago Adams wrote:
> > On Wednesday, November 6, 2019 at 10:33:11 AM UTC-3, Thiago Adams wrote:
> >> Option 2: With restrict signature.
> >> In this case we need a declaration for the 'interface' for foo.
> >> for instance, one name/concept that I would like to use for any
> >> type is destroy. All function destroy have the same signature.
> >>
> >> So the generic interface for destroy could be:
> >>
> >> void destroy(auto);
> >>
> >> and the implementation.
> >>
> >> void x_destroy(struct X* p) : destroy;
> >>
> >> the implementation must follow the destroy contract.
> > ...
> >
> >
> > This feature with contract is similar of some C++ operator
> > overloading.
> >
> > Some operators in C++ have strict contracts. For instance,
> > the operator delete must be:
> >
> > void operator delete(void * p)
> >
> > if I change the return type for instance:
> >
> > void* operator delete(void * p)
> > error: ‘operator delete’ must return type ‘void’
> >
> >
> > In my view, destroy, init, delete , new, swap, clone etc..
> > are 'universal operators', just like + , - 0 and they could exist by
> > default in the C language using this feature of function tags.
> >
> > Not only this, but some algorithms are just a matter of
> > composition and destroy and init are samples of that.
> > In this case the language could generate these operators for
> > us by composition.
> >
> > If we think in terms of sqrt we don't want function overloading
> > with zero or more than one argument.
> > In this aspect _Generic has advantages over function overloading
> > where anything is possible.
>
> I haven't tried function overloading (where you have to look at all
> combinations of parameter and return types to choose the right function,
> and there might still be ambiguities).
>
> Class-based (or method-based) is simpler, and the choice is made on the
> first parameter only. Take this example in fantasy C:
>
> typedef struct {
> void SayMyName(bart &s) {puts("Bart");}
> } bart;
>
> typedef struct {
> void SayMyName(lisa &s) {puts("Lisa");}
> } lisa;
>
> bart B;
> lisa L;
>
> B.SayMyName(); // Bart
> L.SayMyName(); // Lisa
>
> bart.SayMyName(B); // Bart
> lisa.SayMyName(L); // Lisa
>
C++ had some proposals to allow both ways.
https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax
Another alternative I can think of is to create a identifier
at compilation phase.
For instance:
struct X x;
_Join(_ShortName(x), L"_Destroy")(x);
ShortName returns X (without struct) and _Joins
concatenates X and _Destroy resultant in X_Destroy.
This allow us to create the macro 'destroy' solving one place
definition problem of _Generic.
If necessary (to make the compiler simpler) we also can have
just one _MakeIdentifer("%s_Destroy", x);
This would be a complement of _Generic not 100% replacement.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-11-06 22:45 +0100 |
| Message-ID | <qpvett$drj$1@dont-email.me> |
| In reply to | #147669 |
On 06/11/2019 15:26, Bart wrote:
> On 06/11/2019 13:56, Thiago Adams wrote:
>> On Wednesday, November 6, 2019 at 10:33:11 AM UTC-3, Thiago Adams wrote:
>>> Option 2: With restrict signature.
>>> In this case we need a declaration for the 'interface' for foo.
>>> for instance, one name/concept that I would like to use for any
>>> type is destroy. All function destroy have the same signature.
>>>
>>> So the generic interface for destroy could be:
>>>
>>> void destroy(auto);
>>>
>>> and the implementation.
>>>
>>> void x_destroy(struct X* p) : destroy;
>>>
>>> the implementation must follow the destroy contract.
>> ...
>>
>>
>> This feature with contract is similar of some C++ operator
>> overloading.
>>
>> Some operators in C++ have strict contracts. For instance,
>> the operator delete must be:
>>
>> void operator delete(void * p)
>>
>> if I change the return type for instance:
>>
>> void* operator delete(void * p)
>> error: ‘operator delete’ must return type ‘void’
>>
>>
>> In my view, destroy, init, delete , new, swap, clone etc..
>> are 'universal operators', just like + , - 0 and they could exist by
>> default in the C language using this feature of function tags.
>>
>> Not only this, but some algorithms are just a matter of
>> composition and destroy and init are samples of that.
>> In this case the language could generate these operators for
>> us by composition.
>>
>> If we think in terms of sqrt we don't want function overloading
>> with zero or more than one argument.
>> In this aspect _Generic has advantages over function overloading
>> where anything is possible.
>
> I haven't tried function overloading (where you have to look at all
> combinations of parameter and return types to choose the right function,
> and there might still be ambiguities).
>
> Class-based (or method-based) is simpler, and the choice is made on the
> first parameter only. Take this example in fantasy C:
>
> typedef struct {
> void SayMyName(bart &s) {puts("Bart");}
> } bart;
>
> typedef struct {
> void SayMyName(lisa &s) {puts("Lisa");}
> } lisa;
>
> bart B;
> lisa L;
>
> B.SayMyName(); // Bart
> L.SayMyName(); // Lisa
>
> bart.SayMyName(B); // Bart
> lisa.SayMyName(L); // Lisa
You can get a fair amount of that today in C, though it is a little more
verbose:
#include <stdio.h>
typedef struct bart {
void (*SayMyName)(struct bart*);
} bart;
void bart_SayMyName(struct bart* s) { puts("Bart"); }
#define bart_init { bart_SayMyName }
typedef struct lisa {
void (*SayMyName)(struct lisa*);
} lisa;
void lisa_SayMyName(struct lisa * s) { puts("Lisa"); }
#define lisa_init { lisa_SayMyName }
bart B = bart_init;
lisa L = lisa_init;
void foo(void) {
B.SayMyName(&B);
L.SayMyName(&L);
bart_SayMyName(&B);
lisa_SayMyName(&L);
}
Not perfect, but some people find such constructs useful.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2019-11-29 14:35 -0800 |
| Message-ID | <qrs6ft$13to$1@gioia.aioe.org> |
| In reply to | #147680 |
On 11/6/2019 1:45 PM, David Brown wrote:
> On 06/11/2019 15:26, Bart wrote:
>> On 06/11/2019 13:56, Thiago Adams wrote:
>>> On Wednesday, November 6, 2019 at 10:33:11 AM UTC-3, Thiago Adams wrote:
[...]
>> Class-based (or method-based) is simpler, and the choice is made on
>> the first parameter only. Take this example in fantasy C:
>>
>> typedef struct {
>> void SayMyName(bart &s) {puts("Bart");}
>> } bart;
>>
>> typedef struct {
>> void SayMyName(lisa &s) {puts("Lisa");}
>> } lisa;
>>
>> bart B;
>> lisa L;
>>
>> B.SayMyName(); // Bart
>> L.SayMyName(); // Lisa
>>
>> bart.SayMyName(B); // Bart
>> lisa.SayMyName(L); // Lisa
>
>
> You can get a fair amount of that today in C, though it is a little more
> verbose:
>
> #include <stdio.h>
>
> typedef struct bart {
> void (*SayMyName)(struct bart*);
> } bart;
>
> void bart_SayMyName(struct bart* s) { puts("Bart"); }
> #define bart_init { bart_SayMyName }
>
> typedef struct lisa {
> void (*SayMyName)(struct lisa*);
> } lisa;
>
> void lisa_SayMyName(struct lisa * s) { puts("Lisa"); }
> #define lisa_init { lisa_SayMyName }
>
> bart B = bart_init;
> lisa L = lisa_init;
>
> void foo(void) {
> B.SayMyName(&B);
> L.SayMyName(&L);
>
> bart_SayMyName(&B);
> lisa_SayMyName(&L);
> }
>
>
> Not perfect, but some people find such constructs useful.
>
Indeed, not perfect but can be made to work. Fwiw, here is a hack that I
created in the past:
https://pastebin.com/raw/f52a443b1
_______________________________________
/* Interfaces
____________________________________________________________________*/
#include <stddef.h>
struct object_prv_vtable {
int (*fp_destroy) (void* const);
};
struct device_prv_vtable {
int (*fp_read) (void* const, void*, size_t);
int (*fp_write) (void* const, void const*, size_t);
};
struct device_vtable {
struct object_prv_vtable const object;
struct device_prv_vtable const device;
};
struct device {
struct device_vtable const* vtable;
};
#define object_destroy(mp_self) ( \
(mp_self)->vtable->object.fp_destroy((mp_self)) \
)
#define device_read(mp_self, mp_buf, mp_size) ( \
(mp_self)->vtable->device.fp_read((mp_self), (mp_buf), (mp_size)) \
)
#define device_write(mp_self, mp_buf, mp_size) ( \
(mp_self)->vtable->device.fp_write((mp_self), (mp_buf), (mp_size)) \
)
/* Sample Header (usb_drive.h)
____________________________________________________________________*/
#if ! defined(USB_HEADER_H)
#define USB_HEADER_H
extern int usb_drive_create(struct device** const);
#endif
/* Sample Impl (usb_drive.c)
____________________________________________________________________*/
/* #include "usb_drive.c" */
#include <stdio.h>
#include <stdlib.h>
struct usb_drive {
struct device device;
/* whatever */
};
static int usb_drive_object_destroy(void* const);
static int usb_drive_device_read(void* const, void*, size_t);
static int usb_drive_device_write(void* const, void const*, size_t);
static struct device_vtable const g_table = {
{ /* object */
usb_drive_object_destroy
},
{ /* device */
usb_drive_device_read,
usb_drive_device_write
}
};
int usb_drive_create(
struct device** const pself
) {
struct usb_drive* const self = malloc(sizeof(*self));
if (self) {
self->device.vtable = &g_table;
*pself = &self->device;
return 0;
}
return -1;
}
int usb_drive_object_destroy(
void* const self_
) {
struct usb_drive* const self = self_;
printf("usb_drive_object_destroy(%p)\n", (void*)self);
free(self_);
return 0;
}
int usb_drive_device_read(
void* const self_,
void* buf,
size_t size
) {
struct usb_drive* const self = self_;
printf("usb_drive_device_read(%p, %p, %lu)\n",
(void*)self, buf, (unsigned long)size);
return 0;
}
int usb_drive_device_write(
void* const self_,
void const* buf,
size_t size
) {
struct usb_drive* const self = self_;
printf("usb_drive_device_write(%p, %p, %lu)\n",
(void*)self, buf, (unsigned long)size);
return 0;
}
/* Sample Application
____________________________________________________________________*/
void read_write(
struct device* const self
) {
char buf[100];
device_read(self, buf, 50);
device_write(self, buf, 5);
}
int main(void) {
struct device* a_device;
if (! usb_drive_create(&a_device)) {
read_write(a_device);
object_destroy(a_device);
}
return 0;
}
_______________________________________
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-11-29 23:23 +0000 |
| Message-ID | <87h82m2rom.fsf@bsb.me.uk> |
| In reply to | #148304 |
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
<cut>
> struct object_prv_vtable {
> int (*fp_destroy) (void* const);
> };
>
>
> struct device_prv_vtable {
> int (*fp_read) (void* const, void*, size_t);
> int (*fp_write) (void* const, void const*, size_t);
> };
Why so many different uses of const?
In a function prototype (where there is no function body), qualifying a
parameter as const is just noise. The caller knows the function can't
modify any object in the calling context using that parameter since
that's just how call by value works.
Qualifying a pointer /target/ is useful in all cases where it can be
done. It tells the reader something useful about the function, and it
allows the compiler to check it.
<cut>
--
Ben.
[toc] | [prev] | [next] | [standalone]
Page 3 of 4 — ← Prev page 1 2 [3] 4 Next page →
Back to top | Article view | comp.lang.c
csiph-web