• Hey, guest user. Hope you're enjoying NeoGAF! Have you considered registering for an account? Come join us and add your take to the daily discourse.

Programming |OT| C is better than C++! No, C++ is better than C

Koren

Member
Hey, I've got a question I was hoping I could get some help with. I'm new to programming and I'm taking an intro CS class in Python 3.6.

I'm having trouble understanding the difference between the following two scenarios.

Code:
def f(a,b):
    sumab = a+b
    c = c + sumab

c = 1
f(1,10)

The above produces an unbound local variable error at c = c + sumab. If I instead wrote c = sumab that would be fine, as would d = c + sumab, because the latter would look in the parent frame for c. But from my understanding , doing c = c + sumab makes python think the c on the right of the = is supposed to refer to a c in the local frame which isn't defined yet, and so it gives me an error. To fix it I could add the line "nonlocal c."

My question now is why the following works:

Code:
def countup():
    count = [0]
    def resolve(request):
        if request == "up":
            count[0] = count[0]+1
        elif request == "down":
            count[0] = count[0]-1
        elif request == "currentvalue":
            return count
    return resolve

a = countup()
a("up")

Why is Python cool with me referring to the first value in the list "count" on both sides of the = in the conditionals even though the list "count" is defined in its parent frame, when it has trouble in the previous code doing something similar? I feel like I'm overlooking something really obvious but this was one of those things I thought I understood until I thought about it more.
Well, in your second example, it's required to work so that you can have algebraic closure.

Count is local, even if not in the inner function. When you leave the countup function, since the reference count to the list count is not zero, it doesn't get destroyed.

I'd argue the first case is mostly a safeguard against errors when a global clashes with a local name. I was surprised it's not a runtime error but a "static" one at first time (but it makes sense).

I don't think there's an obvious reason behind this. It's... designed this way, because in both cases it seems to be the best choice.


Edit: let me say that if you're new to programming and this is the kind of things that puzzles you, you're doing great...
 

Koren

Member
To expand on this (hard on phone)

If you had used count = something in the inner function, you still would have needed nonlocal for Python to know that it's the same count. It's not required here because you mutate it and never reassign it. Use a list in the first case and you'll get a working code without no local.


Also, in your first example, I'd argue global is more logical than no local (though it's basically the same here)


The reason can be seen this way: in you first example, the most probable situation is that you forgot to initialize the name c. The fact that There's a global c may be coincidence.

In the second example, the count name declaration can't be far from the inner function that uses it, so it's probably by design.
 

1upsuper

Member
Thank you very much! So in the first case, is " c = c + sumab" considered a reassignment then? And because count[0] += count[0]+1 changes something about the list called count, it's a mutation to what is still the same list "count," just with a new value in the 0th slot?
 

phisheep

NeoGAF's Chief Barrister
If, instead of ...
Code:
count[0] = count[0]+1
... you had ...
Code:
count = [count[0]+1]
... then you'd get a name error flagged.

With the same binding, those two statements should be equivalent

The second one, the assignment to count, binds count locally. The first one, the assignment to count[0] doesn't act as a definition of count, so it uses the one in the surrounding scope.

Language reference 4.2.1 says name binding happens for "targets that are identifiers if occurring in an assignment". "Targets" is the important word here. An assignment to count[0] does not make count itself the target of an assignment.

Thank you very much! So in the first case, is " c = c + sumab" considered a reassignment then? And because count[0] += count[0]+1 changes something about the list called count, it's a mutation to what is still the same list "count," just with a new value in the 0th slot?

Yup - bit late but I got there eventually!
 
I took an Intro to Programming class in the Spring that used Python and I'm taking an Intro to C++ class right now. So glad I took the first class as I'd be completely lost right now.
 

Somnid

Member
So at my new job they use maven. Seems pretty terrible to me but I don't know if the Java ecosystem has anything better.
 

Antagon

Member
So at my new job they use maven. Seems pretty terrible to me but I don't know if the Java ecosystem has anything better.

If you want to try something different you can look into gradle. Allows programmatic configuration with either Groovy or Kotlin.
 

Koren

Member
ppThank you very much! So in the first case, is " c = c + sumab" considered a reassignment then?
Indeed.
And because count[0] += count[0]+1 changes something about the list called count, it's a mutation to what is still the same list "count," just with a new value in the 0th slot?
Exactly... you replace the value at index 0 in count by count[0]+1

I guess you meant = here and not +=


Also, about this... be careful with +=

count += [ 0 ] IS NOT count = count + [ 0 ]

It's count.extend ([ 0 ])

So it's also a mutation (you append 0 to the list, which doesn't change)
 

Koren

Member
Just a collection of examples to help put some light over this list/nonlocal issues...

Case #1
Code:
X = []
Y = X

def foo() :
    X.extend([ 0 ])

foo()

Add 0 to both X and Y (it's the same list, extend mutate the list to add an element)

Case #2
Code:
X = []
Y = X

def foo() :
    X = X + [ 0 ]

foo()
Incorrect because you try to reassign X without declaring it global (Python first read the right part of the expression in foo, and conclude X is global since it hasn't seen yet a local X... but you can't assign to a global name without explicitely declaring it global, so when Python sees the left part, it refuses the function)

Case #3
Code:
X = []
Y = X

def foo() :
    global X
    X = X + [ 0 ]

foo()
Add 0 to X but not to Y, X and Y aren't the same list anymore after call to foo (the second line in foo reassigns the name X to a new list which is the concatenation of the old one and [ 0 ]).



Now, the *strange* things...

Case #4
Code:
X = []
Y = X

def foo() :
    X += [ 0 ]

foo()
Doesn't work, EVEN IF IT'S A MUTATION (and the same operation as extend). You need a global here... Like in :
Code:
X = []
Y = X

def foo() :
    global X
    X += [ 0 ]

foo()
This works, and add 0 to both X and Y, which still refer to the same list.

And even weirder:

Case #5
Code:
X = []
Y = X

def foo() :
    X.__iadd__([ 0 ])

foo()
This one works (add 0 to both X and Y).


This is a bit strange, because += is just syntaxic sugar for __iadd__! And in this case, the syntaxic sugar version doesn't behave like the hidden method one.

I'm still not sure why += need a global, especially when __iadd__ doesn't.

Well, that's not actually true. I believe it's because L += [ 0 ] actually stand for L = L.__iadd( [ 0 ])__ (or it couldn't handle the case of immutable objects), even if in the list case, I'm pretty sure iadd always returns the list itself, and thus the assignment doesn't do anything.

So I guess I actually know the reason, it's just... well...
 
Anyone aware of any resources paid or otherwise that has coding exercises for Swift? I need to keep my skills up but am struggling to come up with stuff to do.
 

sgjackson

Member
super stupid javascript question: i'm doing the bonfire exercises at freecodecamp and one of the early ones is checking for palindromes. it's not super complicated - you just switch the input to lowercase, replace all the non-alphanumeric characters, then reverse that string in a new variable and compare the two. the main thing i'm wondering about is the regular expression to ditch the alphanumeric characters. right now I'm using /[^qwertyuiopasdfghjklzxcvbnm1234567890]/g. i'd use \w but it checks for underscores, so I'm curious what (if any) better way there is to format that expression.
 

benzy

Member
Anyone here pretty comfortable in MIPS Assembly code?

Wanted to check if I translated this C Code to MIPS Assembly correctly.



C code

Code:
int counter = 0;

void change_global(int value)
{
	counter = counter + value;
} 

void main()
{
	change_global(5);
	change_global(10);
}



my MIPS Assembly code

Code:
.data
counter: .word 0

.text
main:
addi $a0, $zero, 5
addi $a1, $zero, 10
jal change_global
addi $v0, $zero, 10
syscall

change_global:
lw $t0, counter($zero)
add $t0, $t0, $a0
add $t0, $t0, $a1
jr $ra
 
Gotta say, as an aspiring developer, I think you guys are the smartest people in the world. I wish I was at your levels.

I'm not really planning on going into programming but it's one of the classes I need to take. The route I'm going right now is basically split into 3 parts: general skills (English, math etc), general computer skills (the C++ class I'm taking is part of this) and then either web development & design or system administration. Right now I have all of the general skills done but two and will only have one general computer skills class after this one. I was originally going to go into web development & design but I took one class for it and struggled badly (still passed though). I talked with my teacher (same teacher for most of the general computer classes) and he said system administrations would both probably be easier for me and also much easier to find work locally, which is a huge deal for me as I really don't want to either have to move or go to another college.
 

Koren

Member
Anyone here pretty comfortable in MIPS Assembly code?

Wanted to check if I translated this C Code to MIPS Assembly correctly.
You want something that has à similar result, or an actual translation?

Béecause it feels strange, for a translation, to change the behaviour of the function to transform two calls into a single one...
 

benzy

Member
You want something that has à similar result, or an actual translation?

Béecause it feels strange, for a translation, to change the behaviour of the function to transform two calls into a single one...

I wasn't quite sure how to it do as an exact translation. But yeah, it should be a direct translation and not just have the same output. Should I jump and link twice in the main function?
 
I wasn't quite sure how to it do as an exact translation. But yeah, it should be a direct translation and not just have the same output. Should I jump and link twice in the main function?

Have you tried compiling it and see what the compiler generates?

Go to godbolt.org, select a mips compiler or use clang with “-triple mips-unknown-unknown” and study what it outputs.

Make sure to pass “-O0 -x c”.
 

Koren

Member
I wasn't quite sure how to it do as an exact translation. But yeah, it should be a direct translation and not just have the same output. Should I jump and link twice in the main function?
At the very least, you should call twice the function, and the function should add only a single argument to count before jumping back (I admit I'm rusty to remember where the argument should sit in usual calling conventions, but I guess a0)
 
Goddamnit C++, you never cease to both shock and horrify me.

Code:
struct foo {
  using int_func = void (int);
  using wtfunc = void (float and) const &&;

  int_func f;
  wtfunc wtf;
};

Questions:

1. What is wrong with this code, and how can you fix it?

2. Alternatively, if nothing is wrong, what does it do?

3. What is sizeof(foo)?
 

Somnid

Member
Goddamnit C++, you never cease to both shock and horrify me.

Code:
struct foo {
  using int_func = void (int);
  using wtfunc = void (float and) const &&;

  int_func f;
  wtfunc wtf;
};

Questions:

1. What is wrong with this code, and how can you fix it?

2. Alternatively, if nothing is wrong, what does it do?

3. What is sizeof(foo)?

Being a complete C/++ novice:

We create a struct foo with 2 function with types:

int => void
(float, constant reference to &&) => void

It has size of 2 function pointers.
 

Koren

Member
1. What is wrong with this code, and how can you fix it?
I guess that's a quiz, so I'd like to avoid getting answers too quickly...

Can you explain what you mean by "wrong"?

I'd say it's syntaxically correct, but I'm not sure that someone who would write this expect to get what he'll get. So would you consider it wrong in this case?

About the third question, I don't remember the sizeof an empty struct... Is it 0 or 1? I wouldn't be surprised to get the same here.
 
Being a complete C/++ novice:

We create a struct foo with 2 function with types:

int => void
(float, constant reference to &&) => void

It has size of 2 function pointers.

Hints:

sizeof(foo) == 1. It doesn’t contains any function pointers.

The using statements are both correct and name actual types, but the declaration of wtf is illegal because you can’t have an instance of this type, even though it’s a legal type.

There’s also another thing I’m not saying it because it’s too stupid to believe, so I’ll see if anyone figures it out

Edit: actually I might be wrong, the declaration of wtf is legal,
But you can’t make a pointer of it, even though you can with int_func
 
Making good progress on my ToDo List application. I am just getting the core functionality right now. I am sure once I have a working application, I will think of improvements and modifications that I can make.

I am glad I haven't given up on this.
 
I have a dumb question about C++. So with Python, you can use IF and AND statements to get a number between two amounts. There's no AND statement in C++ and I was wondering if there was a better way to do this:
Code:
	if (weight <= 0.0) {
		cout << "Error.  Cannot calculate 0 or negative number." << endl;
	}
	else {
		if (weight <= 1) {
			cout << "Shipping is $5.50 per pound.  The cost to ship your package is $" << weight * 5.50 << "." << endl;
		}
		else {
			if (weight <= 5) {
				cout << "Shipping is $4.75 per pound.  The cost to ship your package is $" << weight * 4.75 << "." << endl;
			}
			else {
				if (weight <= 10) {
					cout << "Shipping is $3.00 per pound.  The cost to ship your package is $" << weight * 3.00 << "." << endl;
				}
				else {
					if (weight <= 25) {
						cout << "Shipping is $2.50 per pound.  The cost to ship your package is $" << weight * 2.50 << "." << endl;
					}
					else {
						if (weight <= 500) {
							cout << "Shipping is $2.25 per pound.  The cost to ship your package is $" << weight * 2.25 << "." << endl;
						}
						else {
							cout << "Error.  Package is too heavy to ship." << endl;
						}
					}
				}
			}
		}
	}
 
I have a dumb question about C++. So with Python, you can use IF and AND statements to get a number between two amounts. There's no AND statement in C++ and I was wondering if there was a better way to do this:
Code:
	if (weight <= 0.0) {
		cout << "Error.  Cannot calculate 0 or negative number." << endl;
	}
	else {
		if (weight <= 1) {
			cout << "Shipping is $5.50 per pound.  The cost to ship your package is $" << weight * 5.50 << "." << endl;
		}
		else {
			if (weight <= 5) {
				cout << "Shipping is $4.75 per pound.  The cost to ship your package is $" << weight * 4.75 << "." << endl;
			}
			else {
				if (weight <= 10) {
					cout << "Shipping is $3.00 per pound.  The cost to ship your package is $" << weight * 3.00 << "." << endl;
				}
				else {
					if (weight <= 25) {
						cout << "Shipping is $2.50 per pound.  The cost to ship your package is $" << weight * 2.50 << "." << endl;
					}
					else {
						if (weight <= 500) {
							cout << "Shipping is $2.25 per pound.  The cost to ship your package is $" << weight * 2.25 << "." << endl;
						}
						else {
							cout << "Error.  Package is too heavy to ship." << endl;
						}
					}
				}
			}
		}
	}

C++ has and. Use &&
 
I have a dumb question about C++. So with Python, you can use IF and AND statements to get a number between two amounts. There's no AND statement in C++ and I was wondering if there was a better way to do this:
Code:
	if (weight <= 0.0) {
		cout << "Error.  Cannot calculate 0 or negative number." << endl;
	}
	else {
		if (weight <= 1) {
			cout << "Shipping is $5.50 per pound.  The cost to ship your package is $" << weight * 5.50 << "." << endl;
		}
		else {
			if (weight <= 5) {
				cout << "Shipping is $4.75 per pound.  The cost to ship your package is $" << weight * 4.75 << "." << endl;
			}
			else {
				if (weight <= 10) {
					cout << "Shipping is $3.00 per pound.  The cost to ship your package is $" << weight * 3.00 << "." << endl;
				}
				else {
					if (weight <= 25) {
						cout << "Shipping is $2.50 per pound.  The cost to ship your package is $" << weight * 2.50 << "." << endl;
					}
					else {
						if (weight <= 500) {
							cout << "Shipping is $2.25 per pound.  The cost to ship your package is $" << weight * 2.25 << "." << endl;
						}
						else {
							cout << "Error.  Package is too heavy to ship." << endl;
						}
					}
				}
			}
		}
	}

Can't you do something like

Code:
if (var operator value && part operator value) ?
if (weight >= 1 && weight <= 5)

In C++, && represents AND and || is an OR
You could do a switch statement to make this a little cleaner, too.
 
C++ has and. Use &&

Thanks.

Edit: Got it to work but one thing is throwing me off:

Code:
	else if (weight > 25 && weight <= 500) {
		cout << "Shipping is $2.25 per pound.  The cost to ship your package is $" << weight * 2.25 << "." << endl;
	}
	else
		cout << "Error.  Package is too heavy to ship." << endl;
	}

int main()
{

Why do I not need a } at the end of my void function?
 

That said, what I would do is this:

Code:
void doit(int weight) {
  std::vector<std::pair<int, float>> shipping_costs = {
    {1, 5.50f},
    {5, 4.75f},
    {10, 3.00f},
    {25, 2.5f},
    {500, 2.25f},
  };

  if (weight <= 0) {
    std::cout << "Error.  Cannot calculate 0 or negative number." << std::endl;
    return;
  }
  for (const auto &entry : shipping_costs) {
    if (weight > entry.first)
      continue;
    std::cout << "Shipping is $" << entry.second << " per pound.  The cost to ship your package is $" << weight * entry.second << "." << std::endl;
    return;
  };

  std::cout << "Error.  Package is too heavy to ship." << std::endl;
}
 
Thanks.

Edit: Got it to work but one thing is throwing me off:

Code:
	else if (weight > 25 && weight <= 500) {
		cout << "Shipping is $2.25 per pound.  The cost to ship your package is $" << weight * 2.25 << "." << endl;
	}
	else
		cout << "Error.  Package is too heavy to ship." << endl;
	}

int main()
{

Why do I not need a } at the end of my void function?

What do you mean? As in why do you need to complete a block of code on a method that doesn't have a return type?

All functions will need to have a final } to signify the end of the function. Think of them like sentences in English. A method without a closing bracket is like a run-on sentence.

I don't use Python much so maybe I am misinterpreting what you're asking.
 
I guess that's a quiz, so I'd like to avoid getting answers too quickly...

Can you explain what you mean by "wrong"?

I'd say it's syntaxically correct, but I'm not sure that someone who would write this expect to get what he'll get. So would you consider it wrong in this case?

About the third question, I don't remember the sizeof an empty struct... Is it 0 or 1? I wouldn't be surprised to get the same here.

Here's a better question. What do you expect happens when you try to compile this?

Code:
using int_func = void (int);
using wtfunc = void (float and) const &&;

struct foo {
  int_func f;
  wtfunc wtf;
};

void foo::wtf(float and) const && {
    std::cout << "value = " << and << std::endl;
}

int main(int argc, char **argv) {

    int_func *ip = nullptr;
    wtfunc *wp = nullptr;

    foo f;

    constexpr int size = sizeof(&foo::f) + sizeof(&foo::wtf);
    static_assert(sizeof(foo) >= size, "fail!");  // Using >= to account for alignment.
    f.wtf(3.0f);
    foo().wtf(3.0f);

    f.f(1);
    foo().f(1);
    return 0;
}

Will it succeed? And if not, where will it fail?
 
What do you mean? As in why do you need to complete a block of code on a method that doesn't have a return type?

All functions will need to have a final } to signify the end of the function. Think of them like sentences in English. A method without a closing bracket is like a run-on sentence.

I don't use Python much so maybe I am misinterpreting what you're asking.

Oh never mind. I was thinking I had a { after my last else statement.
 

firehawk12

Subete no aware
Hey, I had a python question.

I'm trying to format floats so that they look like currency.

So 25.4395453 should be 25.44.

I'm using round(value, 2) to do it, but I'm running into a problem with numbers that have a 0 at the end.

Like 15.5014 is returning 15.5 instead of 15.50. Is there somethihng I can do to the round function force it to return 15.50?
 
Hey, I had a python question.

I'm trying to format floats so that they look like currency.

So 25.4395453 should be 25.44.

I'm using round(value, 2) to do it, but I'm running into a problem with numbers that have a 0 at the end.

Like 15.5014 is returning 15.5 instead of 15.50. Is there somethihng I can do to the round function force it to return 15.50?


Try “{0:.2f}”.format(n)
 
That worked, but can you explain what's happening in this line? I'm not quite sure what the format function is doing.

You need to understand the distinction between what number the floating pointer number physically represents versus how you print it. They're two completely separate concepts.

For starters, not every real number can even be represented precisely (after all, there are an infinite number of them).

So whatever you see printed on your screen is not necessarily the same as the actual number represented by the bits of the floating point number.

The reason this is important is because calling a math function like round is the wrong thing to use if you want the number to look a certain way when you print it. All that does is re-write the bits of the internal number to be slightly different. But it *still* has to go through the same complicated algorithm of interepreting the bits in order to print it.

From the purely mathematical perspective, 12.5 is basically the same as 12.50, so the round function is not the right tool to express this distinction, for that you need to control how the number is displayed, which is the job of a print statement or format function.

Of course, fi you just go to print a number like "print n" then the python intepreter picks some sane default specifications regarding how many decimals to print. In this case though, you didn't want the defaults, you wanted something else.

format is a member function of the string class, and in a way it's like a regular expression in the sense that it's a little embedded mini-language. The way it works is that anything inside of {} is Treated as a "format specifier", and anything outside of {} is just printed. the arguments to the function specify arguments to each thing inside of the various {}.

So, for example "abc{0}def".format(12) says "take the format string 'abc{0}def' and apply the number 12 to it.

abc is not inside of curly braces and neither is def, so those will just get printed. The stuff inside the {} is a 0, which means "the 0th argument to the format function". So in this simple example, it prints abc, then the 0th argument to the format function (which is 12), then def. So the output will be "abc12def".

But you can put more complicated stuff in there as well. If you follow the 0 by a colon, then the stuff after the colon specifies *how* to format it. The rules are different for each type, but in the case of floats, .2f means "print it as a floating point number with 2 decimal points"

So, "{0:.2f}".format(n) means "print the first argument -- which is the variable n -- and is a floating point -- with 2 decimals".
 

Koren

Member
Try ”{0:.2f}".format(n)

For people that are not completely at ease with Python, I found removing the syntaxic sugar here can help...

You can use
Code:
str.format( "The result is {:.2f}", n )
very much like most fprintf and variants in other languages.

The fact that you can replace the "str" with the first argument is at the root of OO programming, but in some cases, it's just hard for beginners.

The most obvious example would be
Code:
"".join( [ "a", "b", "c" ] )
as an equivalent of
Code:
str.join("", [ "a", "b", "c" ] )

The thing is, it makes more sense to see join as a list method, not a str method, but since it can only work on list of strings, the method is on the string separator... But use the shortened version and it gets really really bad.

Here's a better question. What do you expect happens when you try to compile this?
That put some light on your code... Isn't "and" just a drop-in replacement for && because some locales didn't have & in their pagecode like half a century ago?

I've wondered whether it was also working for rvalues references, but when I see
Code:
    std::cout << "value = " << and << std::endl;
I can't see how it could work...


At least, I'm glad I wasn't wrong about the size. But I'm still not sure what the user WANTS to write here.

About the assert, why would the compiler store the functions inside an instance of the struct/class? When you check the size of an instance of the class, you don't expect the member functions to be in the instance? Or do I miss something?


Beside this, the whole rvalue reference thing and its relation to move mechanics is still new for me (I fully grasp WHY it's needed and WHY it's good, but doing the compiler job of checking the status of each element still often eludes me).

I suspect trying to get a pointer to a rvalue like in the wtfunc *wp = nullptr; is bad or shady, and I guess there's also something with f being a lvalue in f.wtf(3.0f), but again, I have no idea about what you expect to do, so...

If you have a good C++11 reference about this (that start at basics so that I don't miss anything, I'd be interested)



And I can't prevent me thinking that C++ try to find clever way to solve issues you basically don't get in other languages...

And the "yes, but you have control" is less and less a good argument. Same for performance (I'll grant you the control on GC, but still).


I really like C++, and it's still my primary choice for large projects, but that's more and more becase there's plently of librairies I like. But even if C++11 and children are a better C++, it's also more and more a clusterfuck.
 
About the assert, why would the compiler store the functions inside an instance of the struct/class? When you check the size of an instance of the class, you don't expect the member functions to be in the instance? Or do I miss something?
But isn’t “type name;” the way you declare variables? It’s surprising to me that this is not declaring variables

I suspect trying to get a pointer to a rvalue like in the wtfunc *wp = nullptr; is bad or shady
For the pointer issue, the rvalue reference at the end is completely irrelevant. Remove the && and the result is the same. In fact, if you do nothing other than add const (or volatile) to the first type, it still fails

Lookup “abominable function types” if you want to go deeper, it’s completely fucked up
 

Koren

Member
But isn't ”type name;" the way you declare variables? It's surprising to me that this is not declaring variables
Well, when you write
Code:
class foo {
  void bar(int);
}
you declare a function for the class foo, not a variable. You just postpone the time where you'll give the implementation of foo::bar.

The only difference between struct and class is that in struct, elements are public by default instead of private...

We've been trained to think struct as collection of variables, but it's basically a class.

Lookup ”abominable function types" if you want to go deeper, it's completely fucked up
Will do, thanks...
 
Well, when you write
Code:
class foo {
  void bar(int);
}
you declare a function for the class foo, not a variable. You just postpone the time where you'll give the implementation of foo::bar.

Yea but your example doesn’t have the syntax “type name;”, it has the syntax “type name();”

It’s surprising to me that you can declare a function with the first syntax.

Imagine a template class like

Code:
template <typename T>
struct foo {
  T member;
};

You would expect this is a data member yes? But what if you write:

Code:
foo<void (int)> f;

You’ve now injected a member function into this class, which the user can provide the definition of, providing a poir man’s implementation of C# partial classes, since you have a way to allow the user to write a function which can access the private members of a class.
 

Jokab

Member
When cpp_king and Koren get into a discussion, I just casually observe. Two geniuses, as far as I am concerned.

I had the privilege of having not two, but three of that kind of people in my closest group of friends at uni, we were a group of five in total. They were all suuper bright people and I have no doubt that they played a huge part in me becoming the programmer I am today and getting through uni as easily as I did.
 
I had the privilege of having not two, but three of that kind of people in my closest group of friends at uni, we were a group of five in total. They were all suuper bright people and I have no doubt that they played a huge part in me becoming the programmer I am today and getting through uni as easily as I did.

They both have been generous in helping me in my studies, especially Koren, so I really appreciate them. I love when I see the two of them go on. It's really awesome to see.
 

Koren

Member
I'm a newbie in terms of C++ compared to Cpp_is_King... But I find the development of new versions of C++ fascinating, and that's really interesting to learn about it, and I'm grateful to Cpp_is_king to discuss it here...

Yea but your example doesn’t have the syntax “type name;”, it has the syntax “type name();”

It’s surprising to me that you can declare a function with the first syntax.
Yes, I agree that it's surprising (for C++ at the very least). At least, it's not natural to me, but I don't do that much "experimental" C++, I stick to things I know well enough.

It can definitively even be misleading, and if I wasn't expecting something strange from the question, I would probably have read it wrong.

The thing is, I really see the "using" as a kind of advanced (and better) preprocessor. So I usually do a "substitution" when I try to understand a program.

And that's the problem (at least for me): it quickly becomes overwhelming when you have to remember a lot of declarations to understand what's going on...


Imagine a template class like

Code:
template <typename T>
struct foo {
  T member;
};

You would expect this is a data member yes? But what if you write:

Code:
foo<void (int)> f;

You’ve now injected a member function into this class, which the user can provide the definition of, providing a poir man’s implementation of C# partial classes, since you have a way to allow the user to write a function which can access the private members of a class.
Now, that's a clever trick I hadn't thought about (or seen yet)...

I still don't know if I should be amazed or scared with what you can do (or hack) with templates... I just want modules so that I don't have inflated header files with code in them.
 
I think metaclasses, should they ever be standardized, will replace a lot of crazy template use.

The example I gave here uses what’s called “abominable function types”, which are a relatively new discovery.

And by discovery, I mean they weren’t intended, it was something that fell out naturally from the type system, and people only found them on accident.

What makes them “abominable” is that while they are perfectly legal types in the type system, you cannot ever have an instance of the type, or even an instance of a pointer to the type. The weird thing is they’re actually needed in some contexts, even though nothing can ever have an abominable type.

So yea, this is what I meant about C++ never ceasing to horrify me :)
 
Top Bottom