473,320 Members | 1,846 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

What is a good idiom for handling a lazy object?

What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?
(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }
};
(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};
Jul 22 '05 #1
12 2763
Siemel Naran wrote:
What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?
(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }
};
(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};


I just want to acknowledge having looked at this post. I this is a good
question, but my requier a bit more background. I did a google on lazy
object, and found this: http://c2.com/cgi/wiki?LazyObject

I know Stroustrup covers something similar to this in TC++PL(SE), I hope to
be able to revisit the topic soon. It would probably help me evaluate your
code if you explained just a bit more in your own words what your design
objectives are.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #2
"Siemel Naran" <Si*********@REMOVE.att.net> wrote...
What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?
(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }
void calculate() const { z = x+y; calculated = true; }
};
(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};


I am not sure why you need to make such a long way around it. Besides,
I was always told that if you need to use dynamic_cast, you should re-
approach your design, it may have too many interdependencies.

Victor
Jul 22 '05 #3
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message news:28-
I just want to acknowledge having looked at this post. I this is a good
question, but my requier a bit more background. I did a google on lazy
object, and found this: http://c2.com/cgi/wiki?LazyObject
Right, that describes it well.
I know Stroustrup covers something similar to this in TC++PL(SE), I hope to be able to revisit the topic soon. It would probably help me evaluate your
code if you explained just a bit more in your own words what your design
objectives are.


I have created a Select object. Option 1 is for the constructor to open the
SQL connection, run the query, etc. Option 2 is for the constructor to just
store the function argument parameters. Only when we start iterating with
Select::for_each or whatever, then open the connection, do the query, etc.
This way we only open the connection when we really need it. Also, we
mininimize the number of connections, because we don't want temporary Select
objects such as those returned from functions to open a connection.

As another example I have written,

class Income
{
public:
...

double total() const
{
if (!m_hastotal)
{
m_total=
d_salary
+d_interest+d_dividends
+d_shortterm+d_longterm
;
m_hastotal=true;
}
return m_total;
}
private:
double d_salary;
double d_interest;
double d_dividends;
double d_shortterm;
double d_longterm;
mutable bool m_hastotal;
mutable double m_total;
This way a second call to income.total() doesn't have to do any
calculations. Not that adding 5 doubles is a big deal anyway, but I was
just playing around here.
Jul 22 '05 #4
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:p2Hec.123685$K91.338613@attbi_s02...
"Siemel Naran" <Si*********@REMOVE.att.net> wrote...

What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?
(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }


void calculate() const { z = x+y; calculated = true; }


Thanks, good catch!
};
(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};


I am not sure why you need to make such a long way around it. Besides,
I was always told that if you need to use dynamic_cast, you should re-
approach your design, it may have too many interdependencies.


The second way seems good for complex objects as we construct a whole new
object like Eval whose constructor garauntees all parts of the objects (the
private member variables) are initialized properly. Using the 1st way means
we have a super-class with all the variables (to store the lazy parameters x
and y, as well as the result variables), and it seems fine for simple
classes like my Income example in the other post and the class above. For
more complex classes the 2nd way forces the use of a constructor, which is a
nice way to fully initialize an object.

And yes, the use of dynamic_cast is a little bothersome, but it's really
just an if statement. I think it's OK in this context because class Thing
knows about the existence of class Lazy and Eval, and these are probably all
in one cpp file.
Jul 22 '05 #5
Siemel Naran wrote:
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:p2Hec.123685$K91.338613@attbi_s02...
"Siemel Naran" <Si*********@REMOVE.att.net> wrote...
void calculate() const { z = x+y; calculated = true; }


Thanks, good catch!


Yup. That had me a bit confused.
> (2)
>
> class Answer {
> virtual ~Answer();
> };
Just tracing this through out loud:

Answer doesn't look like a very useful class. I assume you are creating it
to share acommon type, and, in particular the same descructor.
> class Lazy : public Answer {
> public:
> Lazy(double x, double y) : x(x), y(y) { }
> private:
> friend class Eval;
> double x;
> double y;
> };
You've exposed Lazy::x and Lazy::y to Eval.
> class Eval : public Answer {
> public:
> Eval(const Lazy& lazy) : z(calculate(lazy))
I believe you meant to put a semicolon at the end of the above line. No?
> double operator()() const { return z; } This returns Eval::z no matter what. No magic involved, right?
> private:
> double z;
> static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
This doesn't make sense to me. You seem to be returning a value in a
function whose return type is void.

I believe you /can/ access lazy.x and lazy.y because of the friendship
relationship;
> }; > class Thing {
> public:
> Thing(double x, double y) : answer(new Lazy(x, y)) { }
> double operator()() const {
> const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
> if (lazy) {
> answer.reset(new Eval(*lazy));
> }
This seems like a magical incantation to to check the type. Perhaps it's
common in C++, but I find it a bit more subtle than code perhaps should be.
> const Eval * eval = static_cast<const Eval *>(answer.get());
> assert(eval);
I don't like assert. But then I think checked exceptions are a good thing.
Why did you use it here?
> return (*eval)();
> }
> private:
> mutable boost::shared_ptr<Answer> answer;
> };

[snip] And yes, the use of dynamic_cast is a little bothersome, but it's really
just an if statement.
As far as casts go, dynamic_cast seems the least harmful. The only problem I
have with the way it's used it the subtlety of the test. It looks like a
convoluted instanceof test. I hit this example of instanceof on a google:
http://www.artefaktur.com/acdk/docs/...anceof-de.html
I think it's OK in this context because class Thing
knows about the existence of class Lazy and Eval, and these are probably
all in one cpp file.


I'm inclined to believe there is a more concise and direct way of
accomplishing the same goal. But I really don't know what that would be.

This is just something to consider:
http://www.rube-goldberg.com/html/gallery.htm

Please don't take it too seriously, especially since I have not provided a
better solution.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #6
On Mon, 12 Apr 2004 05:48:00 GMT, "Siemel Naran"
<Si*********@REMOVE.att.net> wrote:
What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?
(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }
};
(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};


How about something like this:

template <class T /*, threading policy? */>
class LazyValue
{
public:
typedef boost::function<T()> creator_t;
LazyValue(creator_t creator)
:m_creator(creator){}

T& get()
{
if (m_creator)
{
m_value = m_creator();
//reset creator
m_creator = creator_t();
}
return m_value;
}

private:
T m_value;
boost::function<T()> m_creator;
};

class Thing {
public:
Thing(double x, double y) : x(x), y(y),
z(bind(&Thing::calculate, this)) { }
double operator()() const {
return z.get();
}
private:
double x;
double y;
mutable LazyValue<double> z;
double calculate() const { return x+y; }
};

This idea can be extended to produce policy controlled, lazy, memory
usage limiting caches (I've done so in Java - a C++ implementation
would be much better. The policies were thread safety, minimum cache
size, how long unused references are held onto, etc. We used it for
loading large configuration objects, XML files, schemas, etc.).

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #7
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:p2Hec.123685
class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};


I am not sure why you need to make such a long way around it. Besides,
I was always told that if you need to use dynamic_cast, you should re-
approach your design, it may have too many interdependencies.


Thinking about your comment on dynamic_cast, I can get rid off it and also
the derivation from Answer (though we now store both objects in memory, not
that that's a bad thing).

class Thing {
public:
Thing(double x, double y) : lazy(new Lazy(x, y)) { }
double operator()() const {
if (!eval) eval.reset(new Eval(*lazy));
return (*eval)();
}
private:
boost::shared_ptr<Lazy> lazy;
mutable boost::shared_ptr<Eval> eval;
};
Jul 22 '05 #8
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:3O********************@speakeasy.net...
Siemel Naran wrote:
Eval(const Lazy& lazy) : z(calculate(lazy))


I believe you meant to put a semicolon at the end of the above line. No?


Actualy { }

> double operator()() const { return z; } This returns Eval::z no matter what. No magic involved, right?


Right.
> private:
> double z;
> static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
This doesn't make sense to me. You seem to be returning a value in a
function whose return type is void.


Sorry, the return type should be double.
I believe you /can/ access lazy.x and lazy.y because of the friendship
relationship;

> class Thing {
> public:
> Thing(double x, double y) : answer(new Lazy(x, y)) { }
> double operator()() const {
> const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
> if (lazy) {
> answer.reset(new Eval(*lazy));
> }
This seems like a magical incantation to to check the type. Perhaps it's
common in C++, but I find it a bit more subtle than code perhaps should

be.

Yes, the use of dynamic_cast (or typeid) doesn't seem nice. On the other
hand, the classes Lazy and Eval are so tightly coupled (with one a friend to
the other), and they're probably declared in the same cpp file, so it's not
so bad. But I was thinking about Victor's point, and came up with a
solution that does not use dynamic_cast. Let me know if you think if that
is clearer.
> const Eval * eval = static_cast<const Eval *>(answer.get());
> assert(eval);

I don't like assert. But then I think checked exceptions are a good thing. Why did you use it here?
To assert that if lazy is false then eval must be true. In the other words,
when the lazy object is destroyed the eval object ought to be created. It
checks the logic of the previous if clause. But my other solution does not
have assert.

This is just something to consider:
http://www.rube-goldberg.com/html/gallery.htm


Huh?

Jul 22 '05 #9
"tom_usenet" <to********@hotmail.com> wrote in message
news:l7********************************@4ax.com...
How about something like this:

template <class T /*, threading policy? */>
class LazyValue
{
public:
typedef boost::function<T()> creator_t;
LazyValue(creator_t creator)
:m_creator(creator){}

T& get()
{
if (m_creator)
{
m_value = m_creator();
//reset creator
m_creator = creator_t();
}
return m_value;
}

private:
T m_value;
boost::function<T()> m_creator;
};
Just a side question. Is boost::function<T()> the same as
boost::function<T>? Anyway, this seems similar to my method #2 with the
modification Victor suggested -- not using dynamic_cast, instead store two
objects representing the raw data (class Lazy in my example, m_creator in
yours) and evaluated data (class Eval in my example, m_value in yours).
class Thing {
public:
Thing(double x, double y) : x(x), y(y),
z(bind(&Thing::calculate, this)) { }
double operator()() const {
return z.get();
}
private:
double x;
double y;
mutable LazyValue<double> z;
double calculate() const { return x+y; }
};
Does this boost::function thing handle functions take one, two, or three
arguments?
This idea can be extended to produce policy controlled, lazy, memory
usage limiting caches (I've done so in Java - a C++ implementation
would be much better. The policies were thread safety, minimum cache
size, how long unused references are held onto, etc. We used it for
loading large configuration objects, XML files, schemas, etc.).


Interesting. I didn't think about thread safety. When would it be an
issue? Is it when you create a LazyValue object and pass it to 2 different
threads?

And can you elaborate on this idea of minimum cache size?
Jul 22 '05 #10
"Siemel Naran" <Si*********@REMOVE.att.net> wrote in message news:<k4*******************@bgtnsc05-news.ops.worldnet.att.net>...
What is a good idiom for handling a lazy object?
I think that accessor functions are necessary and sufficient.
I see 2 good possibilities. <snipped code> Any more, any comments? Which way do people here use?


A cursory glance at your code leaves me thinking that you really mean
to ask if there are any C++ idioms for memoizing. This is a more
interesting question, IMHO, and I would be inclined to answer no.
Seldom does a quality C++ library use the same interface for costly
operations as for trivial ones; a more typical C++ idiom would be to
have a costly operation that may return quickly under trivial
conditions. Further, since the underlying semantics for caching block
I/O may be wildly different from those for caching numeric
computations, unifying the interfaces for the two may not be
constructive. Having said all of that, I'm told that the proxy
pattern is useful in developing caching systems.

-cheers,
prs
Jul 22 '05 #11
"anon luker" <ha*********@yahoo.com> wrote in message
A cursory glance at your code leaves me thinking that you really mean
to ask if there are any C++ idioms for memoizing. This is a more
interesting question, IMHO, and I would be inclined to answer no.
What is "memoize"? Could not find it in the Merriam-Webster dictionary.
Seldom does a quality C++ library use the same interface for costly
operations as for trivial ones; a more typical C++ idiom would be to
have a costly operation that may return quickly under trivial
conditions.
Can you give an example?
Further, since the underlying semantics for caching block
I/O may be wildly different from those for caching numeric
computations, unifying the interfaces for the two may not be
constructive. Having said all of that, I'm told that the proxy
pattern is useful in developing caching systems.


What do you mean by sentence #1?
Jul 22 '05 #12
"Siemel Naran" <Si*********@REMOVE.att.net> wrote in message news:<US********************@bgtnsc04-news.ops.worldnet.att.net>...
"anon luker" <ha*********@yahoo.com> wrote in message
A cursory glance at your code leaves me thinking that you really mean
to ask if there are any C++ idioms for memoizing. This is a more
interesting question, IMHO, and I would be inclined to answer no.


What is "memoize"? Could not find it in the Merriam-Webster dictionary.


Google "memoize" - Results 1 - 30 of about 13,000 for memoize. (0.38
seconds)
Seldom does a quality C++ library use the same interface for costly
operations as for trivial ones; a more typical C++ idiom would be to
have a costly operation that may return quickly under trivial
conditions.


Can you give an example?


I/O operations on highly associative large memory stores are a good
example, I think. Do you want to silently cache huge amounts of data?
How do you handle object copy semantics?
Further, since the underlying semantics for caching block
I/O may be wildly different from those for caching numeric
computations, unifying the interfaces for the two may not be
constructive.


What do you mean by sentence #1?


I inferred from your question and your code that you are seeking a
unified caching strategy. My intent was to discourage you by giving
an example of two operations that typically are best cached in
different ways.
Jul 22 '05 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

220
by: Brandon J. Van Every | last post by:
What's better about Ruby than Python? I'm sure there's something. What is it? This is not a troll. I'm language shopping and I want people's answers. I don't know beans about Ruby or have...
28
by: David MacQuigg | last post by:
I'm concerned that with all the focus on obj$func binding, &closures, and other not-so-pretty details of Prothon, that we are missing what is really good - the simplification of classes. There are...
137
by: Philippe C. Martin | last post by:
I apologize in advance for launching this post but I might get enlightment somehow (PS: I am _very_ agnostic ;-). - 1) I do not consider my intelligence/education above average - 2) I am very...
34
by: Steven T. Hatton | last post by:
Pete Vilder mentioned this a few days back. This is the "Compiler-Firewall Idiom", or pimple. It's similar to an approach taken in some Java designs. AAMOF, when I saw it in Java, my first...
4
by: Siemel Naran | last post by:
What is a good idiom for handling a lazy object? I see 2 good possibilities. Any more, any comments? Which way do people here use? (1) class Thing { public: Thing(double x, double y) :...
13
by: Jason Huang | last post by:
Hi, Would someone explain the following coding more detail for me? What's the ( ) for? CurrentText = (TextBox)e.Item.Cells.Controls; Thanks. Jason
41
by: Jordan | last post by:
While writing some code, I realized I had never developed a consistent pattern for checking errors from a method. I have two styles I jump back and forth between, but I'm wondering which is...
15
by: Jiří Paleček | last post by:
Hello, I know the rules for const handling in C++, but I'd like to ask what is the "right" way to use them, eg. when is it appropriate to make a member function const? This came across this...
38
by: Zytan | last post by:
What is the difference between these two lines? Dim args As Object() = New Object() {strText} Dim args As Object() = {strText} args seems usuable from either, say, like so: ...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, youll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shllpp 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.