Coding: Fleeting Thoughts

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

Re: Coding: Fleeting Thoughts

Postby EvanED » Tue Apr 10, 2012 10:42 pm UTC

troyp wrote:Yeah, in Haskell you can often arrange things so that almost any error causes a compile-time error.

Of course, then you start becoming complacent...and when you *do* have a runtime error, suddenly you're shocked and you say "My program compiled, but now it's...it's giving the wrong answer!"

ML too. One of my friends does a lot of coding in O'Caml, and is fond of the saying "if it compiles it's correct".

My own experience of that phrase, at least as applied to SML (which doesn't have as good tool support), is more along the lines of "The difference between something that can go wrong and something that can't possibly go wrong is that when something that can't possibly go wrong goes wrong it usually turns out to be impossible to get at or repair." :-)

But yeah, languages like that give you a lot of tools for dealing with that sort of thing. Unfortunately, while you can do it in C++, it's a bit of a PITA because it doesn't have strong typedefs.
EvanED
 
Posts: 3767
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI

Re: Coding: Fleeting Thoughts

Postby headprogrammingczar » Tue Apr 10, 2012 10:56 pm UTC

To be fair, that's mostly because a good type system filters out all the easy bugs. My experience with Haskell bugs has been "it's not working right; I need to pick better types".
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you
User avatar
headprogrammingczar
 
Posts: 2953
Joined: Mon Oct 22, 2007 5:28 pm UTC
Location: Beaming you up

Re: Coding: Fleeting Thoughts

Postby troyp » Tue Apr 10, 2012 11:29 pm UTC

Yeah, I guess it's inevitable that the most subtle bugs are going to be the ones that often slip through.

Meem1029 wrote:From what I get of it (still learning Haskell), if you're not doing that sort of thing in Haskell you're doing it wrong.

Yeah, to some extent at least. There's a question of how far you take it, but my impression is that more and more, people are learning to take advantage of the type system as a way of writing - not just checking (or even "writing with checking in mind")- code.

EvanED wrote:But yeah, languages like that give you a lot of tools for dealing with that sort of thing. Unfortunately, while you can do it in C++, it's a bit of a PITA because it doesn't have strong typedefs.

I was curious about that. I don't really know C++, but it doesn't seem to have as powerful a type system as Haskell (I guess technically it does, since it's type system is turing complete with the template system, but it's not as expressive).

headprogrammingczar wrote:My experience with Haskell bugs has been "it's not working right; I need to pick better types".

Yeah, I noticed that when I was writing Haskell. After a while, if I was having problems or even just thinking about how to proceed, I'd get lazy and think "the compiler will help me!". So I'd concentrate on designing types and then the program would almost write itself. A lot of the time I'd write a complicated function by trial and error because as soon as the types matched up, it had to be right.
troyp
 
Posts: 398
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Coding: Fleeting Thoughts

Postby Link » Wed Apr 11, 2012 5:13 am UTC

AVR instruction set, Y U NO have efficient logical-shift-by-n operation?

Seriously, I'm already writing part of my code in assembly language because GCC's output uses too many clock cycles; I thought I could manage it, but not if I need to use loops with expensive branching operations.
ahammel wrote:Fox News is the comment section.
User avatar
Link
 
Posts: 724
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: Nowhere, Middle Of

Re: Coding: Fleeting Thoughts

Postby Jplus » Wed Apr 11, 2012 11:43 am UTC

troyp wrote:
EvanED wrote:But yeah, languages like that give you a lot of tools for dealing with that sort of thing. Unfortunately, while you can do it in C++, it's a bit of a PITA because it doesn't have strong typedefs.

I was curious about that. I don't really know C++, but it doesn't seem to have as powerful a type system as Haskell (I guess technically it does, since it's type system is turing complete with the template system, but it's not as expressive).

I full-heartedly agree to both points here... strong typedefs would make typeful programming in C++ a lot better (isn't there some kind of trick available to do it?) and Haskell's type system is more elegant than C++'s, though not really more powerful. Also I think C++ is more explicit (in a good way) about the distinction between types and data.
Hey, like coding? Perhaps you should check out the red spider project.
Feel free to call me Julian. J+ is just an abbreviation.
User avatar
Jplus
 
Posts: 1091
Joined: Wed Apr 21, 2010 12:29 pm UTC

Re: Coding: Fleeting Thoughts

Postby Yakk » Wed Apr 11, 2012 2:22 pm UTC

I cannot think of a way to make a strong typedef in C++. C++ type behavior is determined by its methods, constructors, member and free operators, destructors and free functions that apply to the type. In that context, I'm not sure what a strong typedef would mean, if you don't allow it to be implicitly cast back to the parent type you lose access to (at least) the free functions that are important to the behavior of many a C++ type.

I could make non-interchangable subtypes in C++0x that could be implicitly coverted to, but not from, the base type.

Or by strong typing, do you mean being able to create tuple structures that have the same structure but not the same type? An easy method is to just use an empty named struct{} as a tuple element that tags the type. So:
Code: Select all
struct TwoDimensionalPositionTag {};
typedef std::tuple< int, int, TwoDimensionalPositionTag > Position2;
struct TwoDimensionalVelocityTag {};
typedef std::tuple< int, int, TwoDimensionalVelocityTag > Velocity2;

gives you generic tuples with tags that make them distinct types?
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Ubik » Wed Apr 11, 2012 3:25 pm UTC

Boost seems to have a system for strong typedefs.
User avatar
Ubik
 
Posts: 801
Joined: Thu Oct 18, 2007 3:43 pm UTC

Re: Coding: Fleeting Thoughts

Postby Jplus » Wed Apr 11, 2012 4:10 pm UTC

@Yakk: what I meant, and presumably what EvanED meant, is that it would be great if we could do something like the following in C++:
Code: Select all
strong typedef unsigned int x_coordinate;
strong typedef unsigned int bytecount;

x_coordinate window_left = 100;
x_coordinate window_right = window_left + 500;

bytecount empty_file = 0;
bytecount full_file = empty_file + 0x400000;

x_coordinate myjoke = full_file + window_left;
    // compilation error:
    // no matching function `x_coordinate operator+ (const bytecount&, const x_coordinate&)'


@Ubik: it's good to see that someone made an attempt, but it seems the header you linked to wouldn't yield a compilation error like in the example above. Most of the behaviour is only inherited by casting back to the parent type.
Hey, like coding? Perhaps you should check out the red spider project.
Feel free to call me Julian. J+ is just an abbreviation.
User avatar
Jplus
 
Posts: 1091
Joined: Wed Apr 21, 2010 12:29 pm UTC

Re: Coding: Fleeting Thoughts

Postby EvanED » Wed Apr 11, 2012 4:31 pm UTC

Yakk wrote:In that context, I'm not sure what a strong typedef would mean, if you don't allow it to be implicitly cast back to the parent type you lose access to (at least) the free functions that are important to the behavior of many a C++ type.

I disagree with this sentence.

There's no reason to require such a cast to be implicit. Explicit is fine too... in fact, in some sense that's sort of the point.
EvanED
 
Posts: 3767
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI

Re: Coding: Fleeting Thoughts

Postby headprogrammingczar » Wed Apr 11, 2012 4:46 pm UTC

Newtypes in C might be relevant.
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you
User avatar
headprogrammingczar
 
Posts: 2953
Joined: Mon Oct 22, 2007 5:28 pm UTC
Location: Beaming you up

Re: Coding: Fleeting Thoughts

Postby Yakk » Wed Apr 11, 2012 5:35 pm UTC

Suppose you have a type T with a free operator+.

If you don't bind to free functions, then your "strong typedef" version of T has no operator+.

In effect, your strong typedef implicitly wants some functions that take T to be duplicated for your strong T typedef. But not others.

And why in the world would this work:
bytecount full_file = empty_file + 0x400000;
The thing on the left is a bytecount. The thing on the right is an unsigned int. Why would they be related implicitly? Being able to implicitly go back and forth from the base integer type is what makes C enums so annoying.

bytecount full_file = empty_file + bytecount(0x400000);
or use:
bytecount full_file = empty_file + 0x400000_bytecount;

Now, things get weird with methods. You want to in effect get every method in the base class and duplicate it in the child class, forwarding it back to the base class. But the child class should be unrelated to the base class in a type hierarchy. And the same with functions and operators that use the base class -- if every instance of the base class is replaced with a child class, should it not accept it?

As another example, take swap. A free function that you specialize to get improved swap for your class. If T has a swap, then so should strongtypedef T.

If this isn't the case, then we end up needing to have fine toothed control over what instances of methods or functions that take T that get turned into the same which take D. (Doing this is rather easy, it just takes lots of code -- you have to explicitly forward it).
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Jplus » Wed Apr 11, 2012 5:58 pm UTC

Let T be whatever type, and let D be some strong typedef of T.

Now take the set of all functions that have T somewhere in their signature. When you declare the strong typedef to D, you want each of these functions (so yes, also swap) to be automatically matched by a function in which all instances of T in the signature are replaced by D. As far as I can tell this would be straight-forward to implement in a compiler, but currently it doesn't exist.

You don't want to automatically obtain matching function in which some instances of T are replaced by D while others are not. (As an aside: in the most extreme case, that would amount to the power set in which all possible combinations of T's and D's are available. That's exactly what you get with a state-of-the-art weak typedef.) Of course, you might still implement functions with such signatures by hand, or perhaps there could be a language feature that enables the function if you just declare it to be allowed.

I think this is all there is to be said about the issue. Yakk, you're correct that I was a bit imprecise with the integer literals but it's besides the point.

headprogrammingczar wrote:Newtypes in C might be relevant.

Certainly. That's about the same approach as in the Boost strong typedef header. Currently, the closest you can come to a strong typedef in C or C++ is to wrap your type in a struct (or class) and forward some or all of the functions.
Hey, like coding? Perhaps you should check out the red spider project.
Feel free to call me Julian. J+ is just an abbreviation.
User avatar
Jplus
 
Posts: 1091
Joined: Wed Apr 21, 2010 12:29 pm UTC

Re: Coding: Fleeting Thoughts

Postby headprogrammingczar » Thu Apr 12, 2012 12:47 pm UTC

I'm confused. Isn't automatic lifting the thing strong typedefs are supposed to prevent?
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you
User avatar
headprogrammingczar
 
Posts: 2953
Joined: Mon Oct 22, 2007 5:28 pm UTC
Location: Beaming you up

Re: Coding: Fleeting Thoughts

Postby Jplus » Thu Apr 12, 2012 2:30 pm UTC

I'm confused too. What do we mean by "lifting", exactly? If it doesn't do automatic lifting, are we justified at all in calling it a typedef (from a C++ perspective)?
Hey, like coding? Perhaps you should check out the red spider project.
Feel free to call me Julian. J+ is just an abbreviation.
User avatar
Jplus
 
Posts: 1091
Joined: Wed Apr 21, 2010 12:29 pm UTC

Re: Coding: Fleeting Thoughts

Postby Yakk » Thu Apr 12, 2012 5:40 pm UTC

One could imagine dividing functions that act on a type into two categories.

The first are those that "belong" to the type, and the others are those that "use" the type.

Those that "belong" to the type would, in a strong typedef, be recreated with the new type as arguments.

Those that "use" the type would not.

C++ doesn't have these concepts (well, you could say that methods "belong" to the type, but some free functions are really part of the type definition of a type). But one could imagine a language that did -- ie, where could attach free functions to the type, so when you cloned the type (which is what a strong typedef sort of is) they come along.

Ie, imagine a language where both classes and instances are objects (possibly of a different kind -- maybe classes are compile-time objects, while instances are not), and you can run code on them. Classes can carry with them functions, methods and operations. Instances of a class would know what class they belong to (and might even be allowed to create run-time classes that override some methods/functions/operators of the compile time class, for instance). Classes can have parents to which they dispatch queries that they do not handle.

A strong typedef would then take the class and clone it (at compile time), together with all of the functions, methods and operators on the class, and give it a new name.

Then a third party function or method that takes the original class would not take the strong typedef clone.

Now, you could imagine doing something along the lines of cloning the third party library, unit or class, and creating a new one that takes the strong typedef. Or, extending it at compile time to also take the strong typedef with a terse syntax. So you might say "using my_int: cloneof( unsigned int ); extend namespace std::math unsigned int->my_int;" or something like that.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby troyp » Thu Apr 12, 2012 10:20 pm UTC

I was thinking that one advantage, at least, of the struct approach in C/C++ is that you could choose exactly which operations it makes sense to forward.

In Haskell, you've got type classes (you could think of them as statically-typed duck-typing, I guess: they define an interface and you can make any type an instance of the type class by declaring it and implementing the interface for that class) and a lot of operations/functions are polymorphic over type classes. Also, for a newtype, you can automatically derive any type class which the base class is a member of - so it just takes one line to list which classes of operations you want to operate on the newtype. This is parametric polymorphism, though, not implicit coercion, so you couldn't, say, add an Int and an instance of your newtype integer. You'd have to explicitly covert one. (You actually could add an integer literal, eg "myint + 4", since these are actually polymorphic and can be used as any numeric type)

Yakk wrote:Ie, imagine a language where both classes and instances are objects (possibly of a different kind -- maybe classes are compile-time objects, while instances are not), and you can run code on them. Classes can carry with them functions, methods and operations. Instances of a class would know what class they belong to (and might even be allowed to create run-time classes that override some methods/functions/operators of the compile time class, for instance). Classes can have parents to which they dispatch queries that they do not handle.

There are actually lots of languages like this (with classes created at runtime, though, not compile-time). AFAIK, they're all dynamic languages, though, so strong typedefs aren't a big concern. But if you were using explicit type checking to restrict what values could be passed to functions (which in Python, at least, is discouraged in favour of duck-typing), you could in theory clone classes like this for "strong" typedefs There wouldn't be much point of course: since it would only affect specific checking anyway, you could just set a flag or something.

It would be interesting to see a statitically-typed language that worked like this.

edit: s/API/interface/g
(Not sure why I used "API" in the context of type classes, it was just the term that popped into my head.)
troyp
 
Posts: 398
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Coding: Fleeting Thoughts

Postby Shivahn » Sat Apr 14, 2012 4:29 am UTC

Ok, I'm having a bit of a problem. Or, well, I had a problem, and I fixed it, but don't know if this is the proper way to do it, or what. This is in C++.

I have a class called SWImage that has a dynamic array of images in it, and a destructor that calls a function that checks to see if there's anything there, and if there is, frees the image memory, then frees the array. I have another class, HWImage, that holds images in the hardware memory. The image loader for HWImage, when called with a file name, creates a SWImage object with its constructor that loads the image to software memory, then (originally) passed that object to a member function that converted it to a texture for the hardware image.

So, it looked like this:
Code: Select all
void HWImage::load(std::string filename, int index)
{
    SWImage image(filename);
    makeTexture(image, index);
}


Now, after a great amount of head bashing, I learned that I don't understand destructors. What appears to have been happening is that at the end of makeTexture, the compiler decides that image (which was passed in as an argument) is out of scope, and calls the destructor. makeTexture returns void, and then HWImage::load ends, calling the destructor on image (again).

So my first question is: Is that what was happening?

Now, I fixed the problem by making makeTexture take a SWImage pointer, and passing image in by reference (and changing all image.whatever() calls to image->whatever() ones). So my second question is: Is that the proper way to handle something like this? Or is there another, better way, or big problems with this one?

Edit for oh right, another question:

There are a lot of private variables that makeTexture needs from SWImage that I want to keep private for good practice's sake. My first thought is just to create a bunch of public functions for SWImages, but that's ugly and seems suboptimal. In Scheme I'd do something like pass in a string and then do a case dispatch based on the string, returning whatever variable I need. First of all, is that how to do it in C++? Make a function like getProperty(std::string) with a switch structure? And secondly, if it is... what does it return? A void pointer that I handle by just being careful about what I'm asking for?
User avatar
Shivahn
 
Posts: 2144
Joined: Tue Jan 06, 2009 6:17 am UTC

Re: Coding: Fleeting Thoughts

Postby EvanED » Sat Apr 14, 2012 5:26 am UTC

Shivahn wrote:I have a class called SWImage that has a dynamic array of images in it, and a destructor that calls a function that checks to see if there's anything there

Just a side note... if you have something like
Code: Select all
if (some_pointer != NULL)
    delete some_pointer;

I suggest don't do that; delete works fine if you pass it null. Simplifies and shortens the code.

So, it looked like this:
Code: Select all
void HWImage::load(std::string filename, int index)
{
    SWImage image(filename);
    makeTexture(image, index);
}


Now, after a great amount of head bashing, I learned that I don't understand destructors. What appears to have been happening is that at the end of makeTexture, the compiler decides that image (which was passed in as an argument) is out of scope, and calls the destructor. makeTexture returns void, and then HWImage::load ends, calling the destructor on image (again).

So my first question is: Is that what was happening?

No.
Spoiler:
Not unless makeTexture is calling it somehow. (You have to goof something up for that to happen.) Under "normal" circumstances, image's destructor will run once, when HWImage::load returns.

Things which could cause makeTexture to call the destructor? The most likely one would be if it's calling delete on it by accident. Perhaps makeTexture internally stuffs it into the field of some temporary object, and that object deletes it in its destructor mistakenly. Or makeTexture could take a reference-counted smart pointer which is bad-mannered and has a non-explicit constructor, and that's the object that thinks it owns image.


What is much more likely is makeTexture takes its parameter by value. Then there needs to be a copy made, which is done. When makeTexture returns, that copy is destructed.

However, unless you made the copy constructor work properly (and you don't describe doing that), what will happen is that the temporary will also have pointers to image's data, and when the temporary is destructed it will delete that data, and then image's destructor will again delete that data, giving you your double free.

SWImage should disable its copy constructor (make it private and don't provide a body, or, if you're using Boost, inherit boost::noncopyable) or you need to correctly deal with what happens: you either need to do a deep copy of the data members or you need to reference count them (ideally with a smart pointer from Boost or TR1/C++11).

The same caution applies to operator=, which your compiler supplies for you. Disable it in the same way or make it correct.

Now, I fixed the problem by making makeTexture take a SWImage pointer, and passing image in by reference (and changing all image.whatever() calls to image->whatever() ones). So my second question is: Is that the proper way to handle something like this? Or is there another, better way, or big problems with this one?

As long as you're happy with the behavior, it's fine. Objects are passed by pointer or reference all the time. You just have to be aware that modifications to image made within makeTexture will persist, of course.

There are a lot of private variables that makeTexture needs from SWImage that I want to keep private for good practice's sake. My first thought is just to create a bunch of public functions for SWImages, but that's ugly and seems suboptimal. In Scheme I'd do something like pass in a string and then do a case dispatch based on the string, returning whatever variable I need. First of all, is that how to do it in C++? Make a function like getProperty(std::string) with a switch structure? And secondly, if it is... what does it return? A void pointer that I handle by just being careful about what I'm asking for?

Separate getters for each field are the norm in C++. Don't do the void* thing; that's the sort of thing that makes people like me whine in chat rooms with friends about terrible coding atrocities. :-) (In general, if what you're proposing includes the phrase "I'll just be careful about what I'm asking for" it's probably a bad idea. You only have to be wrong once and you wind up with something which can easily be a nightmare bug.)
EvanED
 
Posts: 3767
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI

Re: Coding: Fleeting Thoughts

Postby Yakk » Sat Apr 14, 2012 3:33 pm UTC

troyp wrote:
Yakk wrote:Ie, imagine a language where both classes and instances are objects (possibly of a different kind -- maybe classes are compile-time objects, while instances are not), and you can run code on them. Classes can carry with them functions, methods and operations. Instances of a class would know what class they belong to (and might even be allowed to create run-time classes that override some methods/functions/operators of the compile time class, for instance). Classes can have parents to which they dispatch queries that they do not handle.

There are actually lots of languages like this (with classes created at runtime, though, not compile-time). AFAIK, they're all dynamic languages, though, so strong typedefs aren't a big concern. But if you were using explicit type checking to restrict what values could be passed to functions (which in Python, at least, is discouraged in favour of duck-typing), you could in theory clone classes like this for "strong" typedefs There wouldn't be much point of course: since it would only affect specific checking anyway, you could just set a flag or something.

It would be interesting to see a statitically-typed language that worked like this.
*nod*, in a sense, the message-and-prototype model of OO is easier to write than the class/object duality model, and all prototype model OO have class-as-object.

I find it sad that few modern popular languages have strong compile time capabilities. Generating code isn't the same as doing compile type operations on types. I guess it does double the complexity of your language (look at the C++ template system!), and people just want to "do things".
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Shivahn » Sat Apr 14, 2012 3:37 pm UTC

All right, thanks Evan! That makes sense (I'm glad I'm advanced enough for it to make sense, though I'm sad that my knowledge of C++ is obviously woefully inadequate). I'll disable the default stuff when I get home. makeTexture doesn't alter anything in the software image, so I'm find just passing in a pointer - all calls to the image from within makeTexture are strictly to the data lookup functions.

EvanED wrote:Separate getters for each field are the norm in C++. Don't do the void* thing; that's the sort of thing that makes people like me whine in chat rooms with friends about terrible coding atrocities. :-) (In general, if what you're proposing includes the phrase "I'll just be careful about what I'm asking for" it's probably a bad idea. You only have to be wrong once and you wind up with something which can easily be a nightmare bug.)

Ah, ok. It just seems weird to me to have so many different calls, like getH, getW, getRmask, getPixels, getBytesPerPixel, etc. I know I can combine some of them, but it still just seems weird. Ah well :P
User avatar
Shivahn
 
Posts: 2144
Joined: Tue Jan 06, 2009 6:17 am UTC

Re: Coding: Fleeting Thoughts

Postby Yakk » Sat Apr 14, 2012 3:45 pm UTC

The general rule is that if you have to write a destructor, you also have to write a copy constructor and an operator= (or two operator=s in C++0x).

And if the class "owns" any resources, you have to write a destructor.

"Writing" a copy constructor or operator= can involve simply disabling it so that it doesn't exist/link.

If you like "reference semantics" like in many interpreted languages, where a Foo is really a reference to a Foo object, you might want to look up the "pImpl" pattern where you have a reference counted shared_ptr to the implementation of your class "within" your class.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Shivahn » Sat Apr 14, 2012 4:38 pm UTC

Thanks, I'll look into that. I'm a bit too new to have favored semantics, but that sounds like something I'm interested in.
User avatar
Shivahn
 
Posts: 2144
Joined: Tue Jan 06, 2009 6:17 am UTC

Re: Coding: Fleeting Thoughts

Postby EvanED » Sat Apr 14, 2012 5:58 pm UTC

Shivahn wrote:All right, thanks Evan! That makes sense (I'm glad I'm advanced enough for it to make sense, though I'm sad that my knowledge of C++ is obviously woefully inadequate). I'll disable the default stuff when I get home. makeTexture doesn't alter anything in the software image, so I'm find just passing in a pointer - all calls to the image from within makeTexture are strictly to the data lookup functions.

One other thing I should have mentioned: it's a good idea to make things const if you can. So your getSomeData would be prototyped not as, SomeData * getSomeData() but as SomeData const * getSomeData() const.

Then makeTexture would take a SWImage const * or SWImage const & (the latter is far more idiomatic).

Note too that SWImage const & is the same thing as const SWImage & (and same for *, but not the same as SWImage * const), and that's how you'll usually see that. But I consider it a dumb accident of history that sticks around for no reason other than convention, and prefer the const after the type -- it's the type which is the most interesting and important part of the name.

Ah, ok. It just seems weird to me to have so many different calls, like getH, getW, getRmask, getPixels, getBytesPerPixel, etc. I know I can combine some of them, but it still just seems weird. Ah well :P

Welcome to boilerplate. :-)
EvanED
 
Posts: 3767
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI

Re: Coding: Fleeting Thoughts

Postby Yakk » Sun Apr 15, 2012 5:05 pm UTC

The general rule is that const applies to the part of the type definition before the const keyword.

However, if you put it in the leftmost location, there is no before. So it ends up attaching to the first part of the type (in effect).

There are probably some convoluted type declarations which violate the above common sense approach. :)
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Nautilus » Sun Apr 15, 2012 8:36 pm UTC

HASKELL IS SO COOL :mrgreen:

(Most languages don't have you redefining the entire standard library in the first tutorial)
My flagella bring all the boys to the yard
User avatar
Nautilus
 
Posts: 98
Joined: Thu Feb 25, 2010 1:19 am UTC
Location: That's a strange place to put a piano

Re: Coding: Fleeting Thoughts

Postby Maelstrom. » Sun Apr 15, 2012 11:38 pm UTC

Nautilus wrote:HASKELL IS SO COOL :mrgreen:

(Most languages don't have you redefining the entire standard library in the first tutorial)

I just read an introduction to Lisp that got you to write your own Lisp interpreter in Python, and then write a Lisp interpreter in the Lisp interpreter that you just wrote. Some people are a little crazy!
Maelstrom.
 
Posts: 59
Joined: Tue Oct 21, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby troyp » Mon Apr 16, 2012 3:34 am UTC

Nautilus wrote:HASKELL IS SO COOL :mrgreen:

(Most languages don't have you redefining the entire standard library in the first tutorial)


I think that's pretty typical of functional language tutorials, reimplementing builtin/library functions. It makes perfect sense in a killing-two-birds-with-one-stone way: you learn the standard functions (from the inside out) at the same time you practice coding in the language.

I think other language tutorials should follow this example more (although their (usually) greater verbosity is a disadvantage).
troyp
 
Posts: 398
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Coding: Fleeting Thoughts

Postby Ubik » Mon Apr 16, 2012 1:53 pm UTC

Some time ago I started reading Learn you a Haskell, but didn't get too far before my attention was diverted to other things. I still feel I actually learned something and got at least a bit of how things work in the language. A short while ago I restarted reading, but this time I went on with Real world Haskell and have progressed with it some amount. I still have to admit I haven't actually done the excercises nor done anything real with Haskell otherwise either. It could make things easier.

Anyway, what bothers me is that in both those books single letter names are used a lot - in fact it gives me an impression that it's a typical thing to do. Even though the programming style seems to favor doing things in a short and generic way, non-descriptive naming is annoying. Looks like it's at least in part that way because Haskell seems to generally have an intentional "mathematical" feeling in it and that shows in the coding practices too. Still, I don't like it, as it confuses my little, not that much mathematically inclined - and possibly more importantly - mathematically trained mind.
User avatar
Ubik
 
Posts: 801
Joined: Thu Oct 18, 2007 3:43 pm UTC

Re: Coding: Fleeting Thoughts

Postby headprogrammingczar » Mon Apr 16, 2012 9:40 pm UTC

It's very common for generic functions in Haskell libraries everywhere. When dealing with less generic functions, you get less generic names (though typically still on the short side). Functions that are complex enough to require long names for parameters are generally refactored before they get that large. Names in Haskell convey as little information as they need to, and no less. Usually the definition of an identifier is going to be on the same line as all occurrences of it anyway, and you can't convey any information at all about polymorphic values, besides what's in the type already.

Code: Select all
-- typical non-generic Haskell code (a bit on the verbose side)
-- modify will usually be written as f, because its purpose is obvious from the type
withHandles :: Handle -> Handle -> (String -> String) -> IO ()
withHandles in out modify = do
  datums <- lines <$> hGetContents in
  evaluate (length datums) -- "strictifying" the lazy hGetContents is easier than reading line-by-line
  hPutStrLn out (unlines . map modify $ datums)

-- atypically-verbose Haskell code
-- we already know mappingFunction is a function from the type
-- we already know what element and restOfTheList are because the pattern-match is right there a few characters to the left
map mappingFunction [] = []
map mappingFunction (element : restOfTheList) = (mappingFunction element) : (map mappingFunction restOfTheList)
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you
User avatar
headprogrammingczar
 
Posts: 2953
Joined: Mon Oct 22, 2007 5:28 pm UTC
Location: Beaming you up

Re: Coding: Fleeting Thoughts

Postby troyp » Mon Apr 16, 2012 11:32 pm UTC

@headprogrammingczar: I mostly agree with all that. People sometimes complain that Haskell looks too much like algebra, but to me, algebra is extremely readable for conveying abstract relationships. However, I do sometimes feel that Haskell code is less readable because types have been made unnecessarily general.

FT: I love the use of (x:xs) in pattern matching for "(first element) cons (other elements)". I now find myself using this convention sometimes in python code in similar circumstances.
troyp
 
Posts: 398
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Coding: Fleeting Thoughts

Postby hotaru » Tue Apr 17, 2012 1:10 am UTC

headprogrammingczar wrote:It's very common for generic functions in Haskell libraries everywhere. When dealing with less generic functions, you get less generic names (though typically still on the short side).

i do wish they would have followed that with things like genericLength, genericTake, etc.
Code: Select all
#include <stdio.h>

int main()
{
 struct { unsigned a:3, b:3, c:2; } n = {0};
  do do printf("%hhu\n", *&n);
  while(!(n.a-- && !++n.b));
  while(++n.c);
  return 0; } 
User avatar
hotaru
 
Posts: 931
Joined: Fri Apr 13, 2007 6:54 pm UTC

Re: Coding: Fleeting Thoughts

Postby EvanED » Wed Apr 25, 2012 7:21 pm UTC

I was going to say "it's to bad you can't say something like const auto i = 0 or auto & x = y in C++11" but apparently you can. So that's pretty cool.
EvanED
 
Posts: 3767
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Thu Apr 26, 2012 4:14 pm UTC

That's been my 11 experience so far. A lot of the pieces fit together very nicely and intuitively. Such as lambdas and variadic templates.
Blag.
Ternary computer emulator. Latest version is 0.5 [Nov 29 2008].

Good morning, that's a nice tnetennba.
User avatar
You, sir, name?
 
Posts: 6128
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City

Re: Coding: Fleeting Thoughts

Postby Yakk » Thu Apr 26, 2012 7:56 pm UTC

You, sir, name? wrote:That's been my 11 experience so far. A lot of the pieces fit together very nicely and intuitively. Such as lambdas and variadic templates.

And variadic lambdas.

... damnit.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Thu Apr 26, 2012 11:18 pm UTC

Yakk wrote:
You, sir, name? wrote:That's been my 11 experience so far. A lot of the pieces fit together very nicely and intuitively. Such as lambdas and variadic templates.

And variadic lambdas.

... damnit.


Yeah. I found you can make an event system like the one QT used to have a huge meta-object compiler to ductape onto C++ with like 20 lines of C++11 code. Maybe 100-ish if you want RAII-handles that automatically remove an event handler when it expires (of course modeled after unique_ptr's behavior).
Blag.
Ternary computer emulator. Latest version is 0.5 [Nov 29 2008].

Good morning, that's a nice tnetennba.
User avatar
You, sir, name?
 
Posts: 6128
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City

Re: Coding: Fleeting Thoughts

Postby EvanED » Thu Apr 26, 2012 11:36 pm UTC

To be fair, my understanding is that the MOC provides more than just their signal-slot stuff, also giving you a lot of runtime introspection and reflection capabilities.
EvanED
 
Posts: 3767
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI

Re: Coding: Fleeting Thoughts

Postby Yakk » Fri Apr 27, 2012 4:07 am UTC

I was actually bemoaning the lack of variadic lambdas (lambdas cannot be template functions last I checked, sniff).

And yes, C++0x is missing compiletime reflection. Runtime reflection as a language feature is wasteful, in my opinion: compiletime reflection allows you to easily implement it where and when you want to implement it (and I'd rather have a library implement such a feature -- runtime reflection -- than bake it into the language), and not have to carry the weight otherwise.

I want compile time enumeration of enums, struct members, methods, parent types of a class, methods that a given method overrides, arguments of a function or method -- including the names of each field as both cooked and uncooked literals, and the type of each field as a cooked, uncooked or pure-type value. (cooked/uncooked refer to the same thing as in the user defined literals feature).

That kind of feature would allow reflection and the like to be implemented pretty easily.

A less useful feature that would probably still be used would be the ability to build-your-own interface from tokens passed in. Sort of like macro code creation.

Finally, the ability to examine and audit an expression tree for a block. If you look at microsoft's amp language extension, where they restrict(gpu) the code that a lambda generates, the ability to do the same kind of thing in-language without having to extend the language would be nice. This one is pretty hard, because it would require some pretty serious hooks into the parser, and parsers want their freedom for efficiency reasons. But, once I admit that the restrict(gpu) tokens are worthy of being a language feature (and I believe they are!), being able to do the same without having to modify the language seems tempting...
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Fri Apr 27, 2012 4:59 pm UTC

Yakk wrote:I was actually bemoaning the lack of variadic lambdas (lambdas cannot be template functions last I checked, sniff).


You can't have variadic-function lambdas, but you can have variadic-type lambdas.

That is, this is not valid:
Code: Select all
[](int foo, ...) { }


But this is valid
Code: Select all
#include <functional>
#include <cstdio>

template<typename... T>
std::function<void(T...)> hitMeUpWithAVariadicLambdaBiatch() {
  return [](T... t) { printf("Lambda in the hizzouze\n"); };
}

int main() {
  auto fun = hitMeUpWithAVariadicLambdaBiatch<int, int>();
  fun(3, 5);
}
Blag.
Ternary computer emulator. Latest version is 0.5 [Nov 29 2008].

Good morning, that's a nice tnetennba.
User avatar
You, sir, name?
 
Posts: 6128
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City

Re: Coding: Fleeting Thoughts

Postby Yakk » Fri Apr 27, 2012 8:06 pm UTC

And that lack makes me sad.

Although, it does give me an idea.

Code: Select all
template<typename R, typename U, typename T...>
std::function< std::function< R(T...) >(U) > curry_is_tasty( std::function<R(U, T...)> func )
{
  return [func]( U u ) { return [func,u](T... t){ return func(u,t); }; };
}

Assert( 7 == curry_is_tasty( [](int x, int y) { return x+y; } )(3)(4) );

but I'm still sad because I can't make a template lambda. *sniff*

It isn't as if a template functor isn't easy to write. I guess they just took pity on the compiler writers.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
 
Posts: 10039
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Fri Apr 27, 2012 8:27 pm UTC

I think there are good reasons for not having variadic lambdas. What type would they have? std::function<void(int, ...)> ? What the heck is the compiler supposed to make of that in cases ... appears outside of std::function? What happens if you allocate a std::vector<...>?

You'd basically have to give lambdas a special treatment to get around this.

Sure, I guess you could have a special class for variadic functions, so they're like std::function_variadic<R(A...)> or some such, but that isn't very nice. Besides, variadic functions are one of those legacy things from C that just aren't very C++. It's far better (and infinitely more type safe) to use overloading or containers to achieve the same effect.

By the way, I danced in glee when I discoverd you could do this type of stuff:

Code: Select all
function<int(void)> incrementor() {
  std::shared_ptr<int> i(new int());
  return [i] { return (*i)++; };
}
Blag.
Ternary computer emulator. Latest version is 0.5 [Nov 29 2008].

Good morning, that's a nice tnetennba.
User avatar
You, sir, name?
 
Posts: 6128
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City

PreviousNext

Return to Coding

Who is online

Users browsing this forum: No registered users and 5 guests